xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Host WMI unified implementation
21  */
22 #include "htc_api.h"
23 #include "htc_api.h"
24 #include "wmi_unified_priv.h"
25 #include "qdf_module.h"
26 
27 #ifndef WMI_NON_TLV_SUPPORT
28 #include "wmi_tlv_helper.h"
29 #endif
30 
31 #include <linux/debugfs.h>
32 
33 /* This check for CONFIG_WIN temporary added due to redeclaration compilation
34 error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h
35 which gets included here through ol_if_athvar.h. Eventually it is expected that
36 wmi.h will be removed from wmi_unified_api.h after cleanup, which will need
37 WMI_CMD_HDR to be defined here. */
38 #ifdef CONFIG_WIN
39 /* Copied from wmi.h */
40 #undef MS
41 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
42 #undef SM
43 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
44 #undef WO
45 #define WO(_f)      ((_f##_OFFSET) >> 2)
46 
47 #undef GET_FIELD
48 #define GET_FIELD(_addr, _f) MS(*((uint32_t *)(_addr) + WO(_f)), _f)
49 #undef SET_FIELD
50 #define SET_FIELD(_addr, _f, _val)  \
51 	    (*((uint32_t *)(_addr) + WO(_f)) = \
52 		(*((uint32_t *)(_addr) + WO(_f)) & ~_f##_MASK) | SM(_val, _f))
53 
54 #define WMI_GET_FIELD(_msg_buf, _msg_type, _f) \
55 	    GET_FIELD(_msg_buf, _msg_type ## _ ## _f)
56 
57 #define WMI_SET_FIELD(_msg_buf, _msg_type, _f, _val) \
58 	    SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val)
59 
60 #define WMI_EP_APASS           0x0
61 #define WMI_EP_LPASS           0x1
62 #define WMI_EP_SENSOR          0x2
63 
64 /*
65  *  * Control Path
66  *   */
67 typedef PREPACK struct {
68 	uint32_t	commandId:24,
69 			reserved:2, /* used for WMI endpoint ID */
70 			plt_priv:6; /* platform private */
71 } POSTPACK WMI_CMD_HDR;        /* used for commands and events */
72 
73 #define WMI_CMD_HDR_COMMANDID_LSB           0
74 #define WMI_CMD_HDR_COMMANDID_MASK          0x00ffffff
75 #define WMI_CMD_HDR_COMMANDID_OFFSET        0x00000000
76 #define WMI_CMD_HDR_WMI_ENDPOINTID_MASK        0x03000000
77 #define WMI_CMD_HDR_WMI_ENDPOINTID_OFFSET      24
78 #define WMI_CMD_HDR_PLT_PRIV_LSB               24
79 #define WMI_CMD_HDR_PLT_PRIV_MASK              0xff000000
80 #define WMI_CMD_HDR_PLT_PRIV_OFFSET            0x00000000
81 /* end of copy wmi.h */
82 #endif /* CONFIG_WIN */
83 
84 #define WMI_MIN_HEAD_ROOM 64
85 
86 #ifdef WMI_INTERFACE_EVENT_LOGGING
87 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0))
88 /* TODO Cleanup this backported function */
89 static int wmi_bp_seq_printf(struct seq_file *m, const char *f, ...)
90 {
91 	va_list args;
92 
93 	va_start(args, f);
94 	seq_vprintf(m, f, args);
95 	va_end(args);
96 
97 	return 0;
98 }
99 #else
100 #define wmi_bp_seq_printf(m, fmt, ...) seq_printf((m), fmt, ##__VA_ARGS__)
101 #endif
102 
103 #ifndef MAX_WMI_INSTANCES
104 #ifdef CONFIG_MCL
105 #define MAX_WMI_INSTANCES 1
106 #else
107 #define MAX_WMI_INSTANCES 3
108 #endif
109 #define CUSTOM_MGMT_CMD_DATA_SIZE 4
110 #endif
111 
112 #ifdef CONFIG_MCL
113 /* WMI commands */
114 uint32_t g_wmi_command_buf_idx = 0;
115 struct wmi_command_debug wmi_command_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
116 
117 /* WMI commands TX completed */
118 uint32_t g_wmi_command_tx_cmp_buf_idx = 0;
119 struct wmi_command_debug
120 	wmi_command_tx_cmp_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
121 
122 /* WMI events when processed */
123 uint32_t g_wmi_event_buf_idx = 0;
124 struct wmi_event_debug wmi_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
125 
126 /* WMI events when queued */
127 uint32_t g_wmi_rx_event_buf_idx = 0;
128 struct wmi_event_debug wmi_rx_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
129 #endif
130 
131 #define WMI_COMMAND_RECORD(h, a, b) {					\
132 	if (wmi_log_max_entry <=					\
133 		*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx))	\
134 		*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx) = 0;\
135 	((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\
136 		[*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)]\
137 						.command = a;		\
138 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.		\
139 				wmi_command_log_buf_info.buf)		\
140 		[*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].data,\
141 			b, wmi_record_max_length);			\
142 	((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\
143 		[*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].\
144 		time = qdf_get_log_timestamp();			\
145 	(*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx))++;	\
146 	h->log_info.wmi_command_log_buf_info.length++;			\
147 }
148 
149 #define WMI_COMMAND_TX_CMP_RECORD(h, a, b) {				\
150 	if (wmi_log_max_entry <=					\
151 		*(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))\
152 		*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
153 				p_buf_tail_idx) = 0;			\
154 	((struct wmi_command_debug *)h->log_info.			\
155 		wmi_command_tx_cmp_log_buf_info.buf)			\
156 		[*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
157 				p_buf_tail_idx)].			\
158 							command	= a;	\
159 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.		\
160 				wmi_command_tx_cmp_log_buf_info.buf)	\
161 		[*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
162 			p_buf_tail_idx)].				\
163 		data, b, wmi_record_max_length);			\
164 	((struct wmi_command_debug *)h->log_info.			\
165 		wmi_command_tx_cmp_log_buf_info.buf)			\
166 		[*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
167 				p_buf_tail_idx)].			\
168 		time = qdf_get_log_timestamp();				\
169 	(*(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))++;\
170 	h->log_info.wmi_command_tx_cmp_log_buf_info.length++;		\
171 }
172 
173 #define WMI_EVENT_RECORD(h, a, b) {					\
174 	if (wmi_log_max_entry <=					\
175 		*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx))	\
176 		*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx) = 0;\
177 	((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\
178 		[*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].	\
179 		event = a;						\
180 	qdf_mem_copy(((struct wmi_event_debug *)h->log_info.		\
181 				wmi_event_log_buf_info.buf)		\
182 		[*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].data, b,\
183 		wmi_record_max_length);					\
184 	((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\
185 		[*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].time =\
186 		qdf_get_log_timestamp();				\
187 	(*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx))++;	\
188 	h->log_info.wmi_event_log_buf_info.length++;			\
189 }
190 
191 #define WMI_RX_EVENT_RECORD(h, a, b) {					\
192 	if (wmi_log_max_entry <=					\
193 		*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))\
194 		*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx) = 0;\
195 	((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\
196 		[*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\
197 		event = a;						\
198 	qdf_mem_copy(((struct wmi_event_debug *)h->log_info.		\
199 				wmi_rx_event_log_buf_info.buf)		\
200 		[*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\
201 			data, b, wmi_record_max_length);		\
202 	((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\
203 		[*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\
204 		time =	qdf_get_log_timestamp();			\
205 	(*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))++;	\
206 	h->log_info.wmi_rx_event_log_buf_info.length++;			\
207 }
208 
209 #ifdef CONFIG_MCL
210 uint32_t g_wmi_mgmt_command_buf_idx = 0;
211 struct
212 wmi_command_debug wmi_mgmt_command_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY];
213 
214 /* wmi_mgmt commands TX completed */
215 uint32_t g_wmi_mgmt_command_tx_cmp_buf_idx = 0;
216 struct wmi_command_debug
217 wmi_mgmt_command_tx_cmp_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY];
218 
219 /* wmi_mgmt events when processed */
220 uint32_t g_wmi_mgmt_event_buf_idx = 0;
221 struct wmi_event_debug
222 wmi_mgmt_event_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY];
223 #endif
224 
225 #define WMI_MGMT_COMMAND_RECORD(h, a, b) {                              \
226 	if (wmi_mgmt_log_max_entry <=                                   \
227 		*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)) \
228 		*(h->log_info.wmi_mgmt_command_log_buf_info.		\
229 				p_buf_tail_idx) = 0;			\
230 	((struct wmi_command_debug *)h->log_info.                       \
231 		 wmi_mgmt_command_log_buf_info.buf)                     \
232 		[*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\
233 			command = a;                                    \
234 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.          \
235 				wmi_mgmt_command_log_buf_info.buf)      \
236 		[*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\
237 		data, b,                                                \
238 		wmi_record_max_length);                                	\
239 	((struct wmi_command_debug *)h->log_info.                       \
240 		 wmi_mgmt_command_log_buf_info.buf)                     \
241 		[*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\
242 			time =        qdf_get_log_timestamp();          \
243 	(*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx))++;\
244 	h->log_info.wmi_mgmt_command_log_buf_info.length++;             \
245 }
246 
247 #define WMI_MGMT_COMMAND_TX_CMP_RECORD(h, a, b) {			\
248 	if (wmi_mgmt_log_max_entry <=					\
249 		*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
250 			p_buf_tail_idx))				\
251 		*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
252 			p_buf_tail_idx) = 0;				\
253 	((struct wmi_command_debug *)h->log_info.			\
254 			wmi_mgmt_command_tx_cmp_log_buf_info.buf)	\
255 		[*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
256 				p_buf_tail_idx)].command = a;		\
257 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.		\
258 				wmi_mgmt_command_tx_cmp_log_buf_info.buf)\
259 		[*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
260 			p_buf_tail_idx)].data, b,			\
261 			wmi_record_max_length);				\
262 	((struct wmi_command_debug *)h->log_info.			\
263 			wmi_mgmt_command_tx_cmp_log_buf_info.buf)	\
264 		[*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
265 				p_buf_tail_idx)].time =			\
266 		qdf_get_log_timestamp();				\
267 	(*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.		\
268 			p_buf_tail_idx))++;				\
269 	h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.length++;	\
270 }
271 
272 #define WMI_MGMT_EVENT_RECORD(h, a, b) {				\
273 	if (wmi_mgmt_log_max_entry <=					\
274 		*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))\
275 		*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx) = 0;\
276 	((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\
277 		[*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)]\
278 					.event = a;			\
279 	qdf_mem_copy(((struct wmi_event_debug *)h->log_info.		\
280 				wmi_mgmt_event_log_buf_info.buf)	\
281 		[*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\
282 			data, b, wmi_record_max_length);		\
283 	((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\
284 		[*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\
285 			time = qdf_get_log_timestamp();			\
286 	(*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))++;	\
287 	h->log_info.wmi_mgmt_event_log_buf_info.length++;		\
288 }
289 
290 /* These are defined to made it as module param, which can be configured */
291 uint32_t wmi_log_max_entry = WMI_EVENT_DEBUG_MAX_ENTRY;
292 uint32_t wmi_mgmt_log_max_entry = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
293 uint32_t wmi_record_max_length = WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH;
294 uint32_t wmi_display_size = 100;
295 
296 /**
297  * wmi_log_init() - Initialize WMI event logging
298  * @wmi_handle: WMI handle.
299  *
300  * Return: Initialization status
301  */
302 #ifdef CONFIG_MCL
303 static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle)
304 {
305 	struct wmi_log_buf_t *cmd_log_buf =
306 			&wmi_handle->log_info.wmi_command_log_buf_info;
307 	struct wmi_log_buf_t *cmd_tx_cmpl_log_buf =
308 			&wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info;
309 
310 	struct wmi_log_buf_t *event_log_buf =
311 			&wmi_handle->log_info.wmi_event_log_buf_info;
312 	struct wmi_log_buf_t *rx_event_log_buf =
313 			&wmi_handle->log_info.wmi_rx_event_log_buf_info;
314 
315 	struct wmi_log_buf_t *mgmt_cmd_log_buf =
316 			&wmi_handle->log_info.wmi_mgmt_command_log_buf_info;
317 	struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf =
318 		&wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info;
319 	struct wmi_log_buf_t *mgmt_event_log_buf =
320 			&wmi_handle->log_info.wmi_mgmt_event_log_buf_info;
321 
322 	/* WMI commands */
323 	cmd_log_buf->length = 0;
324 	cmd_log_buf->buf_tail_idx = 0;
325 	cmd_log_buf->buf = wmi_command_log_buffer;
326 	cmd_log_buf->p_buf_tail_idx = &g_wmi_command_buf_idx;
327 	cmd_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
328 
329 	/* WMI commands TX completed */
330 	cmd_tx_cmpl_log_buf->length = 0;
331 	cmd_tx_cmpl_log_buf->buf_tail_idx = 0;
332 	cmd_tx_cmpl_log_buf->buf = wmi_command_tx_cmp_log_buffer;
333 	cmd_tx_cmpl_log_buf->p_buf_tail_idx = &g_wmi_command_tx_cmp_buf_idx;
334 	cmd_tx_cmpl_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
335 
336 	/* WMI events when processed */
337 	event_log_buf->length = 0;
338 	event_log_buf->buf_tail_idx = 0;
339 	event_log_buf->buf = wmi_event_log_buffer;
340 	event_log_buf->p_buf_tail_idx = &g_wmi_event_buf_idx;
341 	event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
342 
343 	/* WMI events when queued */
344 	rx_event_log_buf->length = 0;
345 	rx_event_log_buf->buf_tail_idx = 0;
346 	rx_event_log_buf->buf = wmi_rx_event_log_buffer;
347 	rx_event_log_buf->p_buf_tail_idx = &g_wmi_rx_event_buf_idx;
348 	rx_event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
349 
350 	/* WMI Management commands */
351 	mgmt_cmd_log_buf->length = 0;
352 	mgmt_cmd_log_buf->buf_tail_idx = 0;
353 	mgmt_cmd_log_buf->buf = wmi_mgmt_command_log_buffer;
354 	mgmt_cmd_log_buf->p_buf_tail_idx = &g_wmi_mgmt_command_buf_idx;
355 	mgmt_cmd_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
356 
357 	/* WMI Management commands Tx completed*/
358 	mgmt_cmd_tx_cmp_log_buf->length = 0;
359 	mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0;
360 	mgmt_cmd_tx_cmp_log_buf->buf = wmi_mgmt_command_tx_cmp_log_buffer;
361 	mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx =
362 		&g_wmi_mgmt_command_tx_cmp_buf_idx;
363 	mgmt_cmd_tx_cmp_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
364 
365 	/* WMI Management events when processed*/
366 	mgmt_event_log_buf->length = 0;
367 	mgmt_event_log_buf->buf_tail_idx = 0;
368 	mgmt_event_log_buf->buf = wmi_mgmt_event_log_buffer;
369 	mgmt_event_log_buf->p_buf_tail_idx = &g_wmi_mgmt_event_buf_idx;
370 	mgmt_event_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
371 
372 	qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock);
373 	wmi_handle->log_info.wmi_logging_enable = 1;
374 
375 	return QDF_STATUS_SUCCESS;
376 }
377 #else
378 static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle)
379 {
380 	struct wmi_log_buf_t *cmd_log_buf =
381 			&wmi_handle->log_info.wmi_command_log_buf_info;
382 	struct wmi_log_buf_t *cmd_tx_cmpl_log_buf =
383 			&wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info;
384 
385 	struct wmi_log_buf_t *event_log_buf =
386 			&wmi_handle->log_info.wmi_event_log_buf_info;
387 	struct wmi_log_buf_t *rx_event_log_buf =
388 			&wmi_handle->log_info.wmi_rx_event_log_buf_info;
389 
390 	struct wmi_log_buf_t *mgmt_cmd_log_buf =
391 			&wmi_handle->log_info.wmi_mgmt_command_log_buf_info;
392 	struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf =
393 		&wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info;
394 	struct wmi_log_buf_t *mgmt_event_log_buf =
395 			&wmi_handle->log_info.wmi_mgmt_event_log_buf_info;
396 
397 	wmi_handle->log_info.wmi_logging_enable = 0;
398 
399 	/* WMI commands */
400 	cmd_log_buf->length = 0;
401 	cmd_log_buf->buf_tail_idx = 0;
402 	cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc(
403 		wmi_log_max_entry * sizeof(struct wmi_command_debug));
404 	cmd_log_buf->size = wmi_log_max_entry;
405 
406 	if (!cmd_log_buf->buf) {
407 		qdf_print("no memory for WMI command log buffer..\n");
408 		return QDF_STATUS_E_NOMEM;
409 	}
410 	cmd_log_buf->p_buf_tail_idx = &cmd_log_buf->buf_tail_idx;
411 
412 	/* WMI commands TX completed */
413 	cmd_tx_cmpl_log_buf->length = 0;
414 	cmd_tx_cmpl_log_buf->buf_tail_idx = 0;
415 	cmd_tx_cmpl_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc(
416 		wmi_log_max_entry * sizeof(struct wmi_command_debug));
417 	cmd_tx_cmpl_log_buf->size = wmi_log_max_entry;
418 
419 	if (!cmd_tx_cmpl_log_buf->buf) {
420 		qdf_print("no memory for WMI Command Tx Complete log buffer..\n");
421 		return QDF_STATUS_E_NOMEM;
422 	}
423 	cmd_tx_cmpl_log_buf->p_buf_tail_idx =
424 		&cmd_tx_cmpl_log_buf->buf_tail_idx;
425 
426 	/* WMI events when processed */
427 	event_log_buf->length = 0;
428 	event_log_buf->buf_tail_idx = 0;
429 	event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc(
430 		wmi_log_max_entry * sizeof(struct wmi_event_debug));
431 	event_log_buf->size = wmi_log_max_entry;
432 
433 	if (!event_log_buf->buf) {
434 		qdf_print("no memory for WMI Event log buffer..\n");
435 		return QDF_STATUS_E_NOMEM;
436 	}
437 	event_log_buf->p_buf_tail_idx = &event_log_buf->buf_tail_idx;
438 
439 	/* WMI events when queued */
440 	rx_event_log_buf->length = 0;
441 	rx_event_log_buf->buf_tail_idx = 0;
442 	rx_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc(
443 		wmi_log_max_entry * sizeof(struct wmi_event_debug));
444 	rx_event_log_buf->size = wmi_log_max_entry;
445 
446 	if (!rx_event_log_buf->buf) {
447 		qdf_print("no memory for WMI Event Rx log buffer..\n");
448 		return QDF_STATUS_E_NOMEM;
449 	}
450 	rx_event_log_buf->p_buf_tail_idx = &rx_event_log_buf->buf_tail_idx;
451 
452 	/* WMI Management commands */
453 	mgmt_cmd_log_buf->length = 0;
454 	mgmt_cmd_log_buf->buf_tail_idx = 0;
455 	mgmt_cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc(
456 		wmi_mgmt_log_max_entry * sizeof(struct wmi_command_debug));
457 	mgmt_cmd_log_buf->size = wmi_mgmt_log_max_entry;
458 
459 	if (!mgmt_cmd_log_buf->buf) {
460 		qdf_print("no memory for WMI Management Command log buffer..\n");
461 		return QDF_STATUS_E_NOMEM;
462 	}
463 	mgmt_cmd_log_buf->p_buf_tail_idx = &mgmt_cmd_log_buf->buf_tail_idx;
464 
465 	/* WMI Management commands Tx completed*/
466 	mgmt_cmd_tx_cmp_log_buf->length = 0;
467 	mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0;
468 	mgmt_cmd_tx_cmp_log_buf->buf = (struct wmi_command_debug *)
469 		qdf_mem_malloc(
470 		wmi_mgmt_log_max_entry *
471 		sizeof(struct wmi_command_debug));
472 	mgmt_cmd_tx_cmp_log_buf->size = wmi_mgmt_log_max_entry;
473 
474 	if (!mgmt_cmd_tx_cmp_log_buf->buf) {
475 		qdf_print("no memory for WMI Management Command Tx complete log buffer..\n");
476 		return QDF_STATUS_E_NOMEM;
477 	}
478 	mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx =
479 		&mgmt_cmd_tx_cmp_log_buf->buf_tail_idx;
480 
481 	/* WMI Management events when processed*/
482 	mgmt_event_log_buf->length = 0;
483 	mgmt_event_log_buf->buf_tail_idx = 0;
484 
485 	mgmt_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc(
486 		wmi_mgmt_log_max_entry *
487 		sizeof(struct wmi_event_debug));
488 	mgmt_event_log_buf->size = wmi_mgmt_log_max_entry;
489 
490 	if (!mgmt_event_log_buf->buf) {
491 		qdf_print("no memory for WMI Management Event log buffer..\n");
492 		return QDF_STATUS_E_NOMEM;
493 	}
494 	mgmt_event_log_buf->p_buf_tail_idx = &mgmt_event_log_buf->buf_tail_idx;
495 
496 	qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock);
497 	wmi_handle->log_info.wmi_logging_enable = 1;
498 
499 	return QDF_STATUS_SUCCESS;
500 }
501 #endif
502 
503 /**
504  * wmi_log_buffer_free() - Free all dynamic allocated buffer memory for
505  * event logging
506  * @wmi_handle: WMI handle.
507  *
508  * Return: None
509  */
510 #ifndef CONFIG_MCL
511 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle)
512 {
513 	if (wmi_handle->log_info.wmi_command_log_buf_info.buf)
514 		qdf_mem_free(wmi_handle->log_info.wmi_command_log_buf_info.buf);
515 	if (wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf)
516 		qdf_mem_free(
517 		wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf);
518 	if (wmi_handle->log_info.wmi_event_log_buf_info.buf)
519 		qdf_mem_free(wmi_handle->log_info.wmi_event_log_buf_info.buf);
520 	if (wmi_handle->log_info.wmi_rx_event_log_buf_info.buf)
521 		qdf_mem_free(
522 			wmi_handle->log_info.wmi_rx_event_log_buf_info.buf);
523 	if (wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf)
524 		qdf_mem_free(
525 			wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf);
526 	if (wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf)
527 		qdf_mem_free(
528 		wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf);
529 	if (wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf)
530 		qdf_mem_free(
531 			wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf);
532 	wmi_handle->log_info.wmi_logging_enable = 0;
533 	qdf_spinlock_destroy(&wmi_handle->log_info.wmi_record_lock);
534 }
535 #else
536 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle)
537 {
538 	/* Do Nothing */
539 }
540 #endif
541 
542 /**
543  * wmi_print_cmd_log_buffer() - an output agnostic wmi command log printer
544  * @log_buffer: the command log buffer metadata of the buffer to print
545  * @count: the maximum number of entries to print
546  * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper
547  * @print_priv: any data required by the print method, e.g. a file handle
548  *
549  * Return: None
550  */
551 static void
552 wmi_print_cmd_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count,
553 			 qdf_abstract_print *print, void *print_priv)
554 {
555 	static const int data_len =
556 		WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t);
557 	char str[128];
558 	uint32_t idx;
559 
560 	if (count > log_buffer->size)
561 		count = log_buffer->size;
562 	if (count > log_buffer->length)
563 		count = log_buffer->length;
564 
565 	/* subtract count from index, and wrap if necessary */
566 	idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count;
567 	idx %= log_buffer->size;
568 
569 	print(print_priv, "Time (seconds)      Cmd Id              Payload");
570 	while (count) {
571 		struct wmi_command_debug *cmd_log = (struct wmi_command_debug *)
572 			&((struct wmi_command_debug *)log_buffer->buf)[idx];
573 		uint64_t secs, usecs;
574 		int len = 0;
575 		int i;
576 
577 		qdf_log_timestamp_to_secs(cmd_log->time, &secs, &usecs);
578 		len += scnprintf(str + len, sizeof(str) - len,
579 				 "% 8lld.%06lld    %6u (0x%06x)    ",
580 				 secs, usecs,
581 				 cmd_log->command, cmd_log->command);
582 		for (i = 0; i < data_len; ++i) {
583 			len += scnprintf(str + len, sizeof(str) - len,
584 					 "0x%08x ", cmd_log->data[i]);
585 		}
586 
587 		print(print_priv, str);
588 
589 		--count;
590 		++idx;
591 		if (idx >= log_buffer->size)
592 			idx = 0;
593 	}
594 }
595 
596 /**
597  * wmi_print_event_log_buffer() - an output agnostic wmi event log printer
598  * @log_buffer: the event log buffer metadata of the buffer to print
599  * @count: the maximum number of entries to print
600  * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper
601  * @print_priv: any data required by the print method, e.g. a file handle
602  *
603  * Return: None
604  */
605 static void
606 wmi_print_event_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count,
607 			   qdf_abstract_print *print, void *print_priv)
608 {
609 	static const int data_len =
610 		WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t);
611 	char str[128];
612 	uint32_t idx;
613 
614 	if (count > log_buffer->size)
615 		count = log_buffer->size;
616 	if (count > log_buffer->length)
617 		count = log_buffer->length;
618 
619 	/* subtract count from index, and wrap if necessary */
620 	idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count;
621 	idx %= log_buffer->size;
622 
623 	print(print_priv, "Time (seconds)      Event Id             Payload");
624 	while (count) {
625 		struct wmi_event_debug *event_log = (struct wmi_event_debug *)
626 			&((struct wmi_event_debug *)log_buffer->buf)[idx];
627 		uint64_t secs, usecs;
628 		int len = 0;
629 		int i;
630 
631 		qdf_log_timestamp_to_secs(event_log->time, &secs, &usecs);
632 		len += scnprintf(str + len, sizeof(str) - len,
633 				 "% 8lld.%06lld    %6u (0x%06x)    ",
634 				 secs, usecs,
635 				 event_log->event, event_log->event);
636 		for (i = 0; i < data_len; ++i) {
637 			len += scnprintf(str + len, sizeof(str) - len,
638 					 "0x%08x ", event_log->data[i]);
639 		}
640 
641 		print(print_priv, str);
642 
643 		--count;
644 		++idx;
645 		if (idx >= log_buffer->size)
646 			idx = 0;
647 	}
648 }
649 
650 inline void
651 wmi_print_cmd_log(wmi_unified_t wmi, uint32_t count,
652 		  qdf_abstract_print *print, void *print_priv)
653 {
654 	wmi_print_cmd_log_buffer(
655 		&wmi->log_info.wmi_command_log_buf_info,
656 		count, print, print_priv);
657 }
658 
659 inline void
660 wmi_print_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count,
661 			 qdf_abstract_print *print, void *print_priv)
662 {
663 	wmi_print_cmd_log_buffer(
664 		&wmi->log_info.wmi_command_tx_cmp_log_buf_info,
665 		count, print, print_priv);
666 }
667 
668 inline void
669 wmi_print_mgmt_cmd_log(wmi_unified_t wmi, uint32_t count,
670 		       qdf_abstract_print *print, void *print_priv)
671 {
672 	wmi_print_cmd_log_buffer(
673 		&wmi->log_info.wmi_mgmt_command_log_buf_info,
674 		count, print, print_priv);
675 }
676 
677 inline void
678 wmi_print_mgmt_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count,
679 			      qdf_abstract_print *print, void *print_priv)
680 {
681 	wmi_print_cmd_log_buffer(
682 		&wmi->log_info.wmi_mgmt_command_tx_cmp_log_buf_info,
683 		count, print, print_priv);
684 }
685 
686 inline void
687 wmi_print_event_log(wmi_unified_t wmi, uint32_t count,
688 		    qdf_abstract_print *print, void *print_priv)
689 {
690 	wmi_print_event_log_buffer(
691 		&wmi->log_info.wmi_event_log_buf_info,
692 		count, print, print_priv);
693 }
694 
695 inline void
696 wmi_print_rx_event_log(wmi_unified_t wmi, uint32_t count,
697 		       qdf_abstract_print *print, void *print_priv)
698 {
699 	wmi_print_event_log_buffer(
700 		&wmi->log_info.wmi_rx_event_log_buf_info,
701 		count, print, print_priv);
702 }
703 
704 inline void
705 wmi_print_mgmt_event_log(wmi_unified_t wmi, uint32_t count,
706 			 qdf_abstract_print *print, void *print_priv)
707 {
708 	wmi_print_event_log_buffer(
709 		&wmi->log_info.wmi_mgmt_event_log_buf_info,
710 		count, print, print_priv);
711 }
712 
713 #ifdef CONFIG_MCL
714 const int8_t * const debugfs_dir[MAX_WMI_INSTANCES] = {"WMI0"};
715 #else
716 const int8_t * const debugfs_dir[MAX_WMI_INSTANCES] = {"WMI0", "WMI1", "WMI2"};
717 #endif
718 
719 /* debugfs routines*/
720 
721 /**
722  * debug_wmi_##func_base##_show() - debugfs functions to display content of
723  * command and event buffers. Macro uses max buffer length to display
724  * buffer when it is wraparound.
725  *
726  * @m: debugfs handler to access wmi_handle
727  * @v: Variable arguments (not used)
728  *
729  * Return: Length of characters printed
730  */
731 #define GENERATE_COMMAND_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size)	\
732 	static int debug_wmi_##func_base##_show(struct seq_file *m,	\
733 						void *v)		\
734 	{								\
735 		wmi_unified_t wmi_handle = (wmi_unified_t) m->private;	\
736 		struct wmi_log_buf_t *wmi_log =				\
737 			&wmi_handle->log_info.wmi_##func_base##_buf_info;\
738 		int pos, nread, outlen;					\
739 		int i;							\
740 		uint64_t secs, usecs;					\
741 									\
742 		qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock);	\
743 		if (!wmi_log->length) {					\
744 			qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock);\
745 			return wmi_bp_seq_printf(m,			\
746 			"no elements to read from ring buffer!\n");	\
747 		}							\
748 									\
749 		if (wmi_log->length <= wmi_ring_size)			\
750 			nread = wmi_log->length;			\
751 		else							\
752 			nread = wmi_ring_size;				\
753 									\
754 		if (*(wmi_log->p_buf_tail_idx) == 0)			\
755 			/* tail can be 0 after wrap-around */		\
756 			pos = wmi_ring_size - 1;			\
757 		else							\
758 			pos = *(wmi_log->p_buf_tail_idx) - 1;		\
759 									\
760 		outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\
761 		qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock);	\
762 		while (nread--) {					\
763 			struct wmi_command_debug *wmi_record;		\
764 									\
765 			wmi_record = (struct wmi_command_debug *)	\
766 			&(((struct wmi_command_debug *)wmi_log->buf)[pos]);\
767 			outlen += wmi_bp_seq_printf(m, "CMD ID = %x\n",	\
768 				(wmi_record->command));			\
769 			qdf_log_timestamp_to_secs(wmi_record->time, &secs,\
770 				&usecs);				\
771 			outlen +=					\
772 			wmi_bp_seq_printf(m, "CMD TIME = [%llu.%06llu]\n",\
773 				secs, usecs);				\
774 			outlen += wmi_bp_seq_printf(m, "CMD = ");	\
775 			for (i = 0; i < (wmi_record_max_length/		\
776 					sizeof(uint32_t)); i++)		\
777 				outlen += wmi_bp_seq_printf(m, "%x ",	\
778 					wmi_record->data[i]);		\
779 			outlen += wmi_bp_seq_printf(m, "\n");		\
780 									\
781 			if (pos == 0)					\
782 				pos = wmi_ring_size - 1;		\
783 			else						\
784 				pos--;					\
785 		}							\
786 		return outlen;						\
787 	}								\
788 
789 #define GENERATE_EVENT_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size)	\
790 	static int debug_wmi_##func_base##_show(struct seq_file *m,	\
791 						void *v)		\
792 	{								\
793 		wmi_unified_t wmi_handle = (wmi_unified_t) m->private;	\
794 		struct wmi_log_buf_t *wmi_log =				\
795 			&wmi_handle->log_info.wmi_##func_base##_buf_info;\
796 		int pos, nread, outlen;					\
797 		int i;							\
798 		uint64_t secs, usecs;					\
799 									\
800 		qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock);	\
801 		if (!wmi_log->length) {					\
802 			qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock);\
803 			return wmi_bp_seq_printf(m,			\
804 			"no elements to read from ring buffer!\n");	\
805 		}							\
806 									\
807 		if (wmi_log->length <= wmi_ring_size)			\
808 			nread = wmi_log->length;			\
809 		else							\
810 			nread = wmi_ring_size;				\
811 									\
812 		if (*(wmi_log->p_buf_tail_idx) == 0)			\
813 			/* tail can be 0 after wrap-around */		\
814 			pos = wmi_ring_size - 1;			\
815 		else							\
816 			pos = *(wmi_log->p_buf_tail_idx) - 1;		\
817 									\
818 		outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\
819 		qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock);	\
820 		while (nread--) {					\
821 			struct wmi_event_debug *wmi_record;		\
822 									\
823 			wmi_record = (struct wmi_event_debug *)		\
824 			&(((struct wmi_event_debug *)wmi_log->buf)[pos]);\
825 			qdf_log_timestamp_to_secs(wmi_record->time, &secs,\
826 				&usecs);				\
827 			outlen += wmi_bp_seq_printf(m, "Event ID = %x\n",\
828 				(wmi_record->event));			\
829 			outlen +=					\
830 			wmi_bp_seq_printf(m, "Event TIME = [%llu.%06llu]\n",\
831 				secs, usecs);				\
832 			outlen += wmi_bp_seq_printf(m, "CMD = ");	\
833 			for (i = 0; i < (wmi_record_max_length/		\
834 					sizeof(uint32_t)); i++)		\
835 				outlen += wmi_bp_seq_printf(m, "%x ",	\
836 					wmi_record->data[i]);		\
837 			outlen += wmi_bp_seq_printf(m, "\n");		\
838 									\
839 			if (pos == 0)					\
840 				pos = wmi_ring_size - 1;		\
841 			else						\
842 				pos--;					\
843 		}							\
844 		return outlen;						\
845 	}
846 
847 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_log, wmi_display_size);
848 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_tx_cmp_log, wmi_display_size);
849 GENERATE_EVENT_DEBUG_SHOW_FUNCS(event_log, wmi_display_size);
850 GENERATE_EVENT_DEBUG_SHOW_FUNCS(rx_event_log, wmi_display_size);
851 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_log, wmi_display_size);
852 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_tx_cmp_log,
853 					wmi_display_size);
854 GENERATE_EVENT_DEBUG_SHOW_FUNCS(mgmt_event_log, wmi_display_size);
855 
856 /**
857  * debug_wmi_enable_show() - debugfs functions to display enable state of
858  * wmi logging feature.
859  *
860  * @m: debugfs handler to access wmi_handle
861  * @v: Variable arguments (not used)
862  *
863  * Return: always 1
864  */
865 static int debug_wmi_enable_show(struct seq_file *m, void *v)
866 {
867 	wmi_unified_t wmi_handle = (wmi_unified_t) m->private;
868 
869 	return wmi_bp_seq_printf(m, "%d\n",
870 			wmi_handle->log_info.wmi_logging_enable);
871 }
872 
873 /**
874  * debug_wmi_log_size_show() - debugfs functions to display configured size of
875  * wmi logging command/event buffer and management command/event buffer.
876  *
877  * @m: debugfs handler to access wmi_handle
878  * @v: Variable arguments (not used)
879  *
880  * Return: Length of characters printed
881  */
882 static int debug_wmi_log_size_show(struct seq_file *m, void *v)
883 {
884 
885 	wmi_bp_seq_printf(m, "WMI command/event log max size:%d\n",
886 				wmi_log_max_entry);
887 	return wmi_bp_seq_printf(m,
888 			"WMI management command/events log max size:%d\n",
889 			wmi_mgmt_log_max_entry);
890 }
891 
892 /**
893  * debug_wmi_##func_base##_write() - debugfs functions to clear
894  * wmi logging command/event buffer and management command/event buffer.
895  *
896  * @file: file handler to access wmi_handle
897  * @buf: received data buffer
898  * @count: length of received buffer
899  * @ppos: Not used
900  *
901  * Return: count
902  */
903 #define GENERATE_DEBUG_WRITE_FUNCS(func_base, wmi_ring_size, wmi_record_type)\
904 	static ssize_t debug_wmi_##func_base##_write(struct file *file,	\
905 				const char __user *buf,			\
906 				size_t count, loff_t *ppos)		\
907 	{								\
908 		int k, ret;						\
909 		wmi_unified_t wmi_handle =				\
910 			((struct seq_file *)file->private_data)->private;\
911 		struct wmi_log_buf_t *wmi_log = &wmi_handle->log_info.	\
912 				wmi_##func_base##_buf_info;		\
913 		char locbuf[50];					\
914 									\
915 		if ((!buf) || (count > 50))				\
916 			return -EFAULT;					\
917 									\
918 		if (copy_from_user(locbuf, buf, count))			\
919 			return -EFAULT;					\
920 									\
921 		ret = sscanf(locbuf, "%d", &k);				\
922 		if ((ret != 1) || (k != 0)) {                           \
923 			qdf_print("Wrong input, echo 0 to clear the wmi	buffer\n");\
924 			return -EINVAL;					\
925 		}							\
926 									\
927 		qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock);	\
928 		qdf_mem_zero(wmi_log->buf, wmi_ring_size *		\
929 				sizeof(struct wmi_record_type));	\
930 		wmi_log->length = 0;					\
931 		*(wmi_log->p_buf_tail_idx) = 0;				\
932 		qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock);	\
933 									\
934 		return count;						\
935 	}
936 
937 GENERATE_DEBUG_WRITE_FUNCS(command_log, wmi_log_max_entry,
938 					wmi_command_debug);
939 GENERATE_DEBUG_WRITE_FUNCS(command_tx_cmp_log, wmi_log_max_entry,
940 					wmi_command_debug);
941 GENERATE_DEBUG_WRITE_FUNCS(event_log, wmi_log_max_entry,
942 					wmi_event_debug);
943 GENERATE_DEBUG_WRITE_FUNCS(rx_event_log, wmi_log_max_entry,
944 					wmi_event_debug);
945 GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_log, wmi_mgmt_log_max_entry,
946 					wmi_command_debug);
947 GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_tx_cmp_log,
948 		wmi_mgmt_log_max_entry, wmi_command_debug);
949 GENERATE_DEBUG_WRITE_FUNCS(mgmt_event_log, wmi_mgmt_log_max_entry,
950 					wmi_event_debug);
951 
952 /**
953  * debug_wmi_enable_write() - debugfs functions to enable/disable
954  * wmi logging feature.
955  *
956  * @file: file handler to access wmi_handle
957  * @buf: received data buffer
958  * @count: length of received buffer
959  * @ppos: Not used
960  *
961  * Return: count
962  */
963 static ssize_t debug_wmi_enable_write(struct file *file, const char __user *buf,
964 					size_t count, loff_t *ppos)
965 {
966 	wmi_unified_t wmi_handle =
967 		((struct seq_file *)file->private_data)->private;
968 	int k, ret;
969 	char locbuf[50];
970 
971 	if ((!buf) || (count > 50))
972 		return -EFAULT;
973 
974 	if (copy_from_user(locbuf, buf, count))
975 		return -EFAULT;
976 
977 	ret = sscanf(locbuf, "%d", &k);
978 	if ((ret != 1) || ((k != 0) && (k != 1)))
979 		return -EINVAL;
980 
981 	wmi_handle->log_info.wmi_logging_enable = k;
982 	return count;
983 }
984 
985 /**
986  * debug_wmi_log_size_write() - reserved.
987  *
988  * @file: file handler to access wmi_handle
989  * @buf: received data buffer
990  * @count: length of received buffer
991  * @ppos: Not used
992  *
993  * Return: count
994  */
995 static ssize_t debug_wmi_log_size_write(struct file *file,
996 		const char __user *buf, size_t count, loff_t *ppos)
997 {
998 	return -EINVAL;
999 }
1000 
1001 /* Structure to maintain debug information */
1002 struct wmi_debugfs_info {
1003 	const char *name;
1004 	struct dentry *de[MAX_WMI_INSTANCES];
1005 	const struct file_operations *ops;
1006 };
1007 
1008 #define DEBUG_FOO(func_base) { .name = #func_base,			\
1009 	.ops = &debug_##func_base##_ops }
1010 
1011 /**
1012  * debug_##func_base##_open() - Open debugfs entry for respective command
1013  * and event buffer.
1014  *
1015  * @inode: node for debug dir entry
1016  * @file: file handler
1017  *
1018  * Return: open status
1019  */
1020 #define GENERATE_DEBUG_STRUCTS(func_base)				\
1021 	static int debug_##func_base##_open(struct inode *inode,	\
1022 						struct file *file)	\
1023 	{								\
1024 		return single_open(file, debug_##func_base##_show,	\
1025 				inode->i_private);			\
1026 	}								\
1027 									\
1028 									\
1029 	static struct file_operations debug_##func_base##_ops = {	\
1030 		.open		= debug_##func_base##_open,		\
1031 		.read		= seq_read,				\
1032 		.llseek		= seq_lseek,				\
1033 		.write		= debug_##func_base##_write,		\
1034 		.release	= single_release,			\
1035 	};
1036 
1037 GENERATE_DEBUG_STRUCTS(wmi_command_log);
1038 GENERATE_DEBUG_STRUCTS(wmi_command_tx_cmp_log);
1039 GENERATE_DEBUG_STRUCTS(wmi_event_log);
1040 GENERATE_DEBUG_STRUCTS(wmi_rx_event_log);
1041 GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_log);
1042 GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_tx_cmp_log);
1043 GENERATE_DEBUG_STRUCTS(wmi_mgmt_event_log);
1044 GENERATE_DEBUG_STRUCTS(wmi_enable);
1045 GENERATE_DEBUG_STRUCTS(wmi_log_size);
1046 
1047 struct wmi_debugfs_info wmi_debugfs_infos[] = {
1048 	DEBUG_FOO(wmi_command_log),
1049 	DEBUG_FOO(wmi_command_tx_cmp_log),
1050 	DEBUG_FOO(wmi_event_log),
1051 	DEBUG_FOO(wmi_rx_event_log),
1052 	DEBUG_FOO(wmi_mgmt_command_log),
1053 	DEBUG_FOO(wmi_mgmt_command_tx_cmp_log),
1054 	DEBUG_FOO(wmi_mgmt_event_log),
1055 	DEBUG_FOO(wmi_enable),
1056 	DEBUG_FOO(wmi_log_size),
1057 };
1058 
1059 #define NUM_DEBUG_INFOS (sizeof(wmi_debugfs_infos) /			\
1060 		sizeof(wmi_debugfs_infos[0]))
1061 
1062 /**
1063  * wmi_debugfs_create() - Create debug_fs entry for wmi logging.
1064  *
1065  * @wmi_handle: wmi handle
1066  * @par_entry: debug directory entry
1067  * @id: Index to debug info data array
1068  *
1069  * Return: none
1070  */
1071 static void wmi_debugfs_create(wmi_unified_t wmi_handle,
1072 		struct dentry *par_entry, int id)
1073 {
1074 	int i;
1075 
1076 	if (par_entry == NULL || (id < 0) || (id >= MAX_WMI_INSTANCES))
1077 		goto out;
1078 
1079 	for (i = 0; i < NUM_DEBUG_INFOS; ++i) {
1080 
1081 		wmi_debugfs_infos[i].de[id] = debugfs_create_file(
1082 				wmi_debugfs_infos[i].name, 0644, par_entry,
1083 				wmi_handle, wmi_debugfs_infos[i].ops);
1084 
1085 		if (wmi_debugfs_infos[i].de[id] == NULL) {
1086 			qdf_print("%s: debug Entry creation failed!\n",
1087 					__func__);
1088 			goto out;
1089 		}
1090 	}
1091 
1092 	return;
1093 
1094 out:
1095 	qdf_print("%s: debug Entry creation failed!\n", __func__);
1096 	wmi_log_buffer_free(wmi_handle);
1097 	return;
1098 }
1099 
1100 /**
1101  * wmi_debugfs_remove() - Remove debugfs entry for wmi logging.
1102  * @wmi_handle: wmi handle
1103  * @dentry: debugfs directory entry
1104  * @id: Index to debug info data array
1105  *
1106  * Return: none
1107  */
1108 static void wmi_debugfs_remove(wmi_unified_t wmi_handle)
1109 {
1110 	int i;
1111 	struct dentry *dentry = wmi_handle->log_info.wmi_log_debugfs_dir;
1112 	int id;
1113 
1114 	if (!wmi_handle->log_info.wmi_instance_id)
1115 		return;
1116 
1117 	id = wmi_handle->log_info.wmi_instance_id - 1;
1118 	if (dentry && (!(id < 0) || (id >= MAX_WMI_INSTANCES))) {
1119 		for (i = 0; i < NUM_DEBUG_INFOS; ++i) {
1120 			if (wmi_debugfs_infos[i].de[id])
1121 				wmi_debugfs_infos[i].de[id] = NULL;
1122 		}
1123 	}
1124 
1125 	if (dentry)
1126 		debugfs_remove_recursive(dentry);
1127 
1128 	if (wmi_handle->log_info.wmi_instance_id)
1129 		wmi_handle->log_info.wmi_instance_id--;
1130 }
1131 
1132 /**
1133  * wmi_debugfs_init() - debugfs functions to create debugfs directory and to
1134  * create debugfs enteries.
1135  *
1136  * @h: wmi handler
1137  *
1138  * Return: init status
1139  */
1140 static QDF_STATUS wmi_debugfs_init(wmi_unified_t wmi_handle)
1141 {
1142 	int wmi_index = wmi_handle->log_info.wmi_instance_id;
1143 
1144 	if (wmi_index < MAX_WMI_INSTANCES) {
1145 		wmi_handle->log_info.wmi_log_debugfs_dir =
1146 			debugfs_create_dir(debugfs_dir[wmi_index], NULL);
1147 
1148 		if (!wmi_handle->log_info.wmi_log_debugfs_dir) {
1149 			qdf_print("error while creating debugfs dir for %s\n",
1150 				  debugfs_dir[wmi_index]);
1151 			return QDF_STATUS_E_FAILURE;
1152 		}
1153 
1154 		wmi_debugfs_create(wmi_handle,
1155 				   wmi_handle->log_info.wmi_log_debugfs_dir,
1156 				   wmi_index);
1157 		wmi_handle->log_info.wmi_instance_id++;
1158 	}
1159 
1160 	return QDF_STATUS_SUCCESS;
1161 }
1162 
1163 /**
1164  * wmi_mgmt_cmd_record() - Wrapper function for mgmt command logging macro
1165  *
1166  * @wmi_handle: wmi handle
1167  * @cmd: mgmt command
1168  * @header: pointer to 802.11 header
1169  * @vdev_id: vdev id
1170  * @chanfreq: channel frequency
1171  *
1172  * Return: none
1173  */
1174 void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd,
1175 			void *header, uint32_t vdev_id, uint32_t chanfreq)
1176 {
1177 
1178 	uint32_t data[CUSTOM_MGMT_CMD_DATA_SIZE];
1179 
1180 	data[0] = ((struct wmi_command_header *)header)->type;
1181 	data[1] = ((struct wmi_command_header *)header)->sub_type;
1182 	data[2] = vdev_id;
1183 	data[3] = chanfreq;
1184 
1185 	qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
1186 
1187 	WMI_MGMT_COMMAND_RECORD(wmi_handle, cmd, (uint8_t *)data);
1188 
1189 	qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
1190 }
1191 #else
1192 /**
1193  * wmi_debugfs_remove() - Remove debugfs entry for wmi logging.
1194  * @wmi_handle: wmi handle
1195  * @dentry: debugfs directory entry
1196  * @id: Index to debug info data array
1197  *
1198  * Return: none
1199  */
1200 static void wmi_debugfs_remove(wmi_unified_t wmi_handle) { }
1201 void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd,
1202 			void *header, uint32_t vdev_id, uint32_t chanfreq) { }
1203 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) { }
1204 #endif /*WMI_INTERFACE_EVENT_LOGGING */
1205 qdf_export_symbol(wmi_mgmt_cmd_record);
1206 
1207 int wmi_get_host_credits(wmi_unified_t wmi_handle);
1208 /* WMI buffer APIs */
1209 
1210 #ifdef NBUF_MEMORY_DEBUG
1211 wmi_buf_t
1212 wmi_buf_alloc_debug(wmi_unified_t wmi_handle, uint16_t len, uint8_t *file_name,
1213 			uint32_t line_num)
1214 {
1215 	wmi_buf_t wmi_buf;
1216 
1217 	if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) {
1218 		QDF_ASSERT(0);
1219 		return NULL;
1220 	}
1221 
1222 	wmi_buf = qdf_nbuf_alloc_debug(NULL,
1223 					roundup(len + WMI_MIN_HEAD_ROOM, 4),
1224 					WMI_MIN_HEAD_ROOM, 4, false, file_name,
1225 					line_num);
1226 
1227 	if (!wmi_buf)
1228 		return NULL;
1229 
1230 	/* Clear the wmi buffer */
1231 	OS_MEMZERO(qdf_nbuf_data(wmi_buf), len);
1232 
1233 	/*
1234 	 * Set the length of the buffer to match the allocation size.
1235 	 */
1236 	qdf_nbuf_set_pktlen(wmi_buf, len);
1237 
1238 	return wmi_buf;
1239 }
1240 qdf_export_symbol(wmi_buf_alloc_debug);
1241 
1242 void wmi_buf_free(wmi_buf_t net_buf)
1243 {
1244 	qdf_nbuf_free(net_buf);
1245 }
1246 qdf_export_symbol(wmi_buf_free);
1247 #else
1248 wmi_buf_t wmi_buf_alloc(wmi_unified_t wmi_handle, uint16_t len)
1249 {
1250 	wmi_buf_t wmi_buf;
1251 
1252 	if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) {
1253 		QDF_ASSERT(0);
1254 		return NULL;
1255 	}
1256 
1257 	wmi_buf = qdf_nbuf_alloc(NULL, roundup(len + WMI_MIN_HEAD_ROOM, 4),
1258 				WMI_MIN_HEAD_ROOM, 4, false);
1259 	if (!wmi_buf)
1260 		return NULL;
1261 
1262 	/* Clear the wmi buffer */
1263 	OS_MEMZERO(qdf_nbuf_data(wmi_buf), len);
1264 
1265 	/*
1266 	 * Set the length of the buffer to match the allocation size.
1267 	 */
1268 	qdf_nbuf_set_pktlen(wmi_buf, len);
1269 	return wmi_buf;
1270 }
1271 qdf_export_symbol(wmi_buf_alloc);
1272 
1273 void wmi_buf_free(wmi_buf_t net_buf)
1274 {
1275 	qdf_nbuf_free(net_buf);
1276 }
1277 qdf_export_symbol(wmi_buf_free);
1278 #endif
1279 
1280 /**
1281  * wmi_get_max_msg_len() - get maximum WMI message length
1282  * @wmi_handle: WMI handle.
1283  *
1284  * This function returns the maximum WMI message length
1285  *
1286  * Return: maximum WMI message length
1287  */
1288 uint16_t wmi_get_max_msg_len(wmi_unified_t wmi_handle)
1289 {
1290 	return wmi_handle->max_msg_len - WMI_MIN_HEAD_ROOM;
1291 }
1292 qdf_export_symbol(wmi_get_max_msg_len);
1293 
1294 #ifndef WMI_CMD_STRINGS
1295 static uint8_t *wmi_id_to_name(uint32_t wmi_command)
1296 {
1297 	return "Invalid WMI cmd";
1298 }
1299 
1300 #endif
1301 
1302 #ifdef CONFIG_MCL
1303 static inline void wmi_log_cmd_id(uint32_t cmd_id, uint32_t tag)
1304 {
1305 	WMI_LOGD("Send WMI command:%s command_id:%d htc_tag:%d\n",
1306 		 wmi_id_to_name(cmd_id), cmd_id, tag);
1307 }
1308 
1309 /**
1310  * wmi_is_pm_resume_cmd() - check if a cmd is part of the resume sequence
1311  * @cmd_id: command to check
1312  *
1313  * Return: true if the command is part of the resume sequence.
1314  */
1315 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id)
1316 {
1317 	switch (cmd_id) {
1318 	case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID:
1319 	case WMI_PDEV_RESUME_CMDID:
1320 		return true;
1321 
1322 	default:
1323 		return false;
1324 	}
1325 }
1326 #else
1327 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id)
1328 {
1329 	return false;
1330 }
1331 #endif
1332 
1333 /**
1334  * wmi_unified_cmd_send() - WMI command API
1335  * @wmi_handle: handle to wmi
1336  * @buf: wmi buf
1337  * @len: wmi buffer length
1338  * @cmd_id: wmi command id
1339  *
1340  * Note, it is NOT safe to access buf after calling this function!
1341  *
1342  * Return: 0 on success
1343  */
1344 QDF_STATUS wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf,
1345 				uint32_t len, uint32_t cmd_id)
1346 {
1347 	HTC_PACKET *pkt;
1348 	QDF_STATUS status;
1349 	uint16_t htc_tag = 0;
1350 
1351 	if (wmi_get_runtime_pm_inprogress(wmi_handle)) {
1352 		htc_tag =
1353 			(uint16_t)wmi_handle->ops->wmi_set_htc_tx_tag(
1354 						wmi_handle, buf, cmd_id);
1355 	} else if (qdf_atomic_read(&wmi_handle->is_target_suspended) &&
1356 		(!wmi_is_pm_resume_cmd(cmd_id))) {
1357 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1358 				  "%s: Target is suspended", __func__);
1359 		QDF_ASSERT(0);
1360 		return QDF_STATUS_E_BUSY;
1361 	}
1362 	if (wmi_handle->wmi_stopinprogress) {
1363 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1364 			"WMI  stop in progress\n");
1365 		return QDF_STATUS_E_INVAL;
1366 	}
1367 
1368 #ifndef WMI_NON_TLV_SUPPORT
1369 	/* Do sanity check on the TLV parameter structure */
1370 	if (wmi_handle->target_type == WMI_TLV_TARGET) {
1371 		void *buf_ptr = (void *)qdf_nbuf_data(buf);
1372 
1373 		if (wmi_handle->ops->wmi_check_command_params(NULL, buf_ptr, len, cmd_id)
1374 			!= 0) {
1375 			QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1376 			"\nERROR: %s: Invalid WMI Param Buffer for Cmd:%d",
1377 				__func__, cmd_id);
1378 			return QDF_STATUS_E_INVAL;
1379 		}
1380 	}
1381 #endif
1382 
1383 	if (qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR)) == NULL) {
1384 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1385 			 "%s, Failed to send cmd %x, no memory",
1386 			 __func__, cmd_id);
1387 		return QDF_STATUS_E_NOMEM;
1388 	}
1389 
1390 	WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id);
1391 
1392 	qdf_atomic_inc(&wmi_handle->pending_cmds);
1393 	if (qdf_atomic_read(&wmi_handle->pending_cmds) >=
1394 			wmi_handle->wmi_max_cmds) {
1395 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1396 		    "\n%s: hostcredits = %d", __func__,
1397 		wmi_get_host_credits(wmi_handle));
1398 		htc_dump_counter_info(wmi_handle->htc_handle);
1399 		qdf_atomic_dec(&wmi_handle->pending_cmds);
1400 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1401 			"%s: MAX %d WMI Pending cmds reached.", __func__,
1402 			wmi_handle->wmi_max_cmds);
1403 		QDF_BUG(0);
1404 		return QDF_STATUS_E_BUSY;
1405 	}
1406 
1407 	pkt = qdf_mem_malloc(sizeof(*pkt));
1408 	if (!pkt) {
1409 		qdf_atomic_dec(&wmi_handle->pending_cmds);
1410 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1411 			 "%s, Failed to alloc htc packet %x, no memory",
1412 			 __func__, cmd_id);
1413 		return QDF_STATUS_E_NOMEM;
1414 	}
1415 
1416 	SET_HTC_PACKET_INFO_TX(pkt,
1417 			       NULL,
1418 			       qdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR),
1419 			       wmi_handle->wmi_endpoint_id, htc_tag);
1420 
1421 	SET_HTC_PACKET_NET_BUF_CONTEXT(pkt, buf);
1422 #ifdef CONFIG_MCL
1423 	wmi_log_cmd_id(cmd_id, htc_tag);
1424 #endif
1425 
1426 #ifdef WMI_INTERFACE_EVENT_LOGGING
1427 	if (wmi_handle->log_info.wmi_logging_enable) {
1428 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
1429 		/*
1430 		 * Record 16 bytes of WMI cmd data -
1431 		 * exclude TLV and WMI headers
1432 		 *
1433 		 * WMI mgmt command already recorded in wmi_mgmt_cmd_record
1434 		 */
1435 		if (wmi_handle->ops->is_management_record(cmd_id) == false) {
1436 			WMI_COMMAND_RECORD(wmi_handle, cmd_id,
1437 					qdf_nbuf_data(buf) +
1438 			 wmi_handle->log_info.buf_offset_command);
1439 		}
1440 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
1441 	}
1442 #endif
1443 
1444 	status = htc_send_pkt(wmi_handle->htc_handle, pkt);
1445 
1446 	if (QDF_STATUS_SUCCESS != status) {
1447 		qdf_atomic_dec(&wmi_handle->pending_cmds);
1448 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1449 		   "%s %d, htc_send_pkt failed", __func__, __LINE__);
1450 		qdf_mem_free(pkt);
1451 		return status;
1452 	}
1453 
1454 	return QDF_STATUS_SUCCESS;
1455 }
1456 qdf_export_symbol(wmi_unified_cmd_send);
1457 
1458 /**
1459  * wmi_unified_get_event_handler_ix() - gives event handler's index
1460  * @wmi_handle: handle to wmi
1461  * @event_id: wmi  event id
1462  *
1463  * Return: event handler's index
1464  */
1465 static int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle,
1466 					    uint32_t event_id)
1467 {
1468 	uint32_t idx = 0;
1469 	int32_t invalid_idx = -1;
1470 	struct wmi_soc *soc = wmi_handle->soc;
1471 
1472 	for (idx = 0; (idx < soc->max_event_idx &&
1473 		       idx < WMI_UNIFIED_MAX_EVENT); ++idx) {
1474 		if (wmi_handle->event_id[idx] == event_id &&
1475 		    wmi_handle->event_handler[idx] != NULL) {
1476 			return idx;
1477 		}
1478 	}
1479 
1480 	return invalid_idx;
1481 }
1482 
1483 /**
1484  * wmi_unified_register_event() - register wmi event handler
1485  * @wmi_handle: handle to wmi
1486  * @event_id: wmi event id
1487  * @handler_func: wmi event handler function
1488  *
1489  * Return: 0 on success
1490  */
1491 int wmi_unified_register_event(wmi_unified_t wmi_handle,
1492 				       uint32_t event_id,
1493 				       wmi_unified_event_handler handler_func)
1494 {
1495 	uint32_t idx = 0;
1496 	uint32_t evt_id;
1497 	struct wmi_soc *soc = wmi_handle->soc;
1498 
1499 	if (event_id >= wmi_events_max ||
1500 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
1501 		qdf_print("%s: Event id %d is unavailable\n",
1502 				 __func__, event_id);
1503 		return QDF_STATUS_E_FAILURE;
1504 	}
1505 	evt_id = wmi_handle->wmi_events[event_id];
1506 	if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) {
1507 		qdf_print("%s : event handler already registered 0x%x\n",
1508 		       __func__, evt_id);
1509 		return QDF_STATUS_E_FAILURE;
1510 	}
1511 	if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) {
1512 		qdf_print("%s : no more event handlers 0x%x\n",
1513 		       __func__, evt_id);
1514 		return QDF_STATUS_E_FAILURE;
1515 	}
1516 	idx = soc->max_event_idx;
1517 	wmi_handle->event_handler[idx] = handler_func;
1518 	wmi_handle->event_id[idx] = evt_id;
1519 	qdf_spin_lock_bh(&soc->ctx_lock);
1520 	wmi_handle->ctx[idx] = WMI_RX_UMAC_CTX;
1521 	qdf_spin_unlock_bh(&soc->ctx_lock);
1522 	soc->max_event_idx++;
1523 
1524 	return 0;
1525 }
1526 
1527 /**
1528  * wmi_unified_register_event_handler() - register wmi event handler
1529  * @wmi_handle: handle to wmi
1530  * @event_id: wmi event id
1531  * @handler_func: wmi event handler function
1532  * @rx_ctx: rx execution context for wmi rx events
1533  *
1534  * This API is to support legacy requirements. Will be deprecated in future.
1535  * Return: 0 on success
1536  */
1537 int wmi_unified_register_event_handler(wmi_unified_t wmi_handle,
1538 				       wmi_conv_event_id event_id,
1539 				       wmi_unified_event_handler handler_func,
1540 				       uint8_t rx_ctx)
1541 {
1542 	uint32_t idx = 0;
1543 	uint32_t evt_id;
1544 	struct wmi_soc *soc = wmi_handle->soc;
1545 
1546 	if (event_id >= wmi_events_max ||
1547 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
1548 		qdf_print("%s: Event id %d is unavailable\n",
1549 				 __func__, event_id);
1550 		return QDF_STATUS_E_FAILURE;
1551 	}
1552 	evt_id = wmi_handle->wmi_events[event_id];
1553 
1554 	if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) {
1555 		qdf_print("%s : event handler already registered 0x%x\n",
1556 		       __func__, evt_id);
1557 		return QDF_STATUS_E_FAILURE;
1558 	}
1559 	if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) {
1560 		qdf_print("%s : no more event handlers 0x%x\n",
1561 		       __func__, evt_id);
1562 		return QDF_STATUS_E_FAILURE;
1563 	}
1564 	QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG,
1565 			"Registered event handler for event 0x%8x\n", evt_id);
1566 	idx = soc->max_event_idx;
1567 	wmi_handle->event_handler[idx] = handler_func;
1568 	wmi_handle->event_id[idx] = evt_id;
1569 	qdf_spin_lock_bh(&soc->ctx_lock);
1570 	wmi_handle->ctx[idx] = rx_ctx;
1571 	qdf_spin_unlock_bh(&soc->ctx_lock);
1572 	soc->max_event_idx++;
1573 
1574 	return 0;
1575 }
1576 qdf_export_symbol(wmi_unified_register_event_handler);
1577 
1578 /**
1579  * wmi_unified_unregister_event() - unregister wmi event handler
1580  * @wmi_handle: handle to wmi
1581  * @event_id: wmi event id
1582  *
1583  * Return: 0 on success
1584  */
1585 int wmi_unified_unregister_event(wmi_unified_t wmi_handle,
1586 					 uint32_t event_id)
1587 {
1588 	uint32_t idx = 0;
1589 	uint32_t evt_id;
1590 	struct wmi_soc *soc = wmi_handle->soc;
1591 
1592 	if (event_id >= wmi_events_max ||
1593 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
1594 		qdf_print("%s: Event id %d is unavailable\n",
1595 				 __func__, event_id);
1596 		return QDF_STATUS_E_FAILURE;
1597 	}
1598 	evt_id = wmi_handle->wmi_events[event_id];
1599 
1600 	idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id);
1601 	if (idx == -1) {
1602 		qdf_print("%s : event handler is not registered: evt id 0x%x\n",
1603 		       __func__, evt_id);
1604 		return QDF_STATUS_E_FAILURE;
1605 	}
1606 	wmi_handle->event_handler[idx] = NULL;
1607 	wmi_handle->event_id[idx] = 0;
1608 	--soc->max_event_idx;
1609 	wmi_handle->event_handler[idx] =
1610 		wmi_handle->event_handler[soc->max_event_idx];
1611 	wmi_handle->event_id[idx] =
1612 		wmi_handle->event_id[soc->max_event_idx];
1613 
1614 	return 0;
1615 }
1616 
1617 /**
1618  * wmi_unified_unregister_event_handler() - unregister wmi event handler
1619  * @wmi_handle: handle to wmi
1620  * @event_id: wmi event id
1621  *
1622  * Return: 0 on success
1623  */
1624 int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle,
1625 					 wmi_conv_event_id event_id)
1626 {
1627 	uint32_t idx = 0;
1628 	uint32_t evt_id;
1629 	struct wmi_soc *soc = wmi_handle->soc;
1630 
1631 	if (event_id >= wmi_events_max ||
1632 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
1633 		qdf_print("%s: Event id %d is unavailable\n",
1634 				 __func__, event_id);
1635 		return QDF_STATUS_E_FAILURE;
1636 	}
1637 	evt_id = wmi_handle->wmi_events[event_id];
1638 
1639 	idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id);
1640 	if (idx == -1) {
1641 		qdf_print("%s : event handler is not registered: evt id 0x%x\n",
1642 		       __func__, evt_id);
1643 		return QDF_STATUS_E_FAILURE;
1644 	}
1645 	wmi_handle->event_handler[idx] = NULL;
1646 	wmi_handle->event_id[idx] = 0;
1647 	--soc->max_event_idx;
1648 	wmi_handle->event_handler[idx] =
1649 		wmi_handle->event_handler[soc->max_event_idx];
1650 	wmi_handle->event_id[idx] =
1651 		wmi_handle->event_id[soc->max_event_idx];
1652 
1653 	return 0;
1654 }
1655 qdf_export_symbol(wmi_unified_unregister_event_handler);
1656 
1657 /**
1658  * wmi_process_fw_event_default_ctx() - process in default caller context
1659  * @wmi_handle: handle to wmi
1660  * @htc_packet: pointer to htc packet
1661  * @exec_ctx: execution context for wmi fw event
1662  *
1663  * Event process by below function will be in default caller context.
1664  * wmi internally provides rx work thread processing context.
1665  *
1666  * Return: none
1667  */
1668 static void wmi_process_fw_event_default_ctx(struct wmi_unified *wmi_handle,
1669 		       HTC_PACKET *htc_packet, uint8_t exec_ctx)
1670 {
1671 	wmi_buf_t evt_buf;
1672 	evt_buf = (wmi_buf_t) htc_packet->pPktContext;
1673 
1674 #ifndef CONFIG_MCL
1675 	wmi_handle->rx_ops.wma_process_fw_event_handler_cbk
1676 		(wmi_handle->scn_handle, evt_buf, exec_ctx);
1677 #else
1678 	wmi_handle->rx_ops.wma_process_fw_event_handler_cbk(wmi_handle,
1679 					 evt_buf, exec_ctx);
1680 #endif
1681 
1682 	return;
1683 }
1684 
1685 /**
1686  * wmi_process_fw_event_worker_thread_ctx() - process in worker thread context
1687  * @wmi_handle: handle to wmi
1688  * @htc_packet: pointer to htc packet
1689  *
1690  * Event process by below function will be in worker thread context.
1691  * Use this method for events which are not critical and not
1692  * handled in protocol stack.
1693  *
1694  * Return: none
1695  */
1696 static void wmi_process_fw_event_worker_thread_ctx
1697 		(struct wmi_unified *wmi_handle, HTC_PACKET *htc_packet)
1698 {
1699 	wmi_buf_t evt_buf;
1700 
1701 	evt_buf = (wmi_buf_t) htc_packet->pPktContext;
1702 
1703 	qdf_spin_lock_bh(&wmi_handle->eventq_lock);
1704 	qdf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf);
1705 	qdf_spin_unlock_bh(&wmi_handle->eventq_lock);
1706 	qdf_queue_work(0, wmi_handle->wmi_rx_work_queue,
1707 			&wmi_handle->rx_event_work);
1708 
1709 	return;
1710 }
1711 
1712 /**
1713  * wmi_get_pdev_ep: Get wmi handle based on endpoint
1714  * @soc: handle to wmi soc
1715  * @ep: endpoint id
1716  *
1717  * Return: none
1718  */
1719 static struct wmi_unified *wmi_get_pdev_ep(struct wmi_soc *soc,
1720 						HTC_ENDPOINT_ID ep)
1721 {
1722 	uint32_t i;
1723 
1724 	for (i = 0; i < WMI_MAX_RADIOS; i++)
1725 		if (soc->wmi_endpoint_id[i] == ep)
1726 			break;
1727 
1728 	if (i == WMI_MAX_RADIOS)
1729 		return NULL;
1730 
1731 	return soc->wmi_pdev[i];
1732 }
1733 
1734 /**
1735  * wmi_control_rx() - process fw events callbacks
1736  * @ctx: handle to wmi
1737  * @htc_packet: pointer to htc packet
1738  *
1739  * Return: none
1740  */
1741 static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet)
1742 {
1743 	struct wmi_soc *soc = (struct wmi_soc *) ctx;
1744 	struct wmi_unified *wmi_handle;
1745 	wmi_buf_t evt_buf;
1746 	uint32_t id;
1747 	uint32_t idx = 0;
1748 	enum wmi_rx_exec_ctx exec_ctx;
1749 
1750 	evt_buf = (wmi_buf_t) htc_packet->pPktContext;
1751 
1752 	wmi_handle = wmi_get_pdev_ep(soc, htc_packet->Endpoint);
1753 	if (wmi_handle == NULL) {
1754 		qdf_print
1755 		("%s :unable to get wmi_handle to Endpoint %d\n",
1756 			__func__, htc_packet->Endpoint);
1757 		qdf_nbuf_free(evt_buf);
1758 		return;
1759 	}
1760 
1761 	id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
1762 	idx = wmi_unified_get_event_handler_ix(wmi_handle, id);
1763 	if (qdf_unlikely(idx == A_ERROR)) {
1764 		WMI_LOGD("%s :event handler is not registered: event id 0x%x\n",
1765 				 __func__, id);
1766 		qdf_nbuf_free(evt_buf);
1767 		return;
1768 	}
1769 	qdf_spin_lock_bh(&soc->ctx_lock);
1770 	exec_ctx = wmi_handle->ctx[idx];
1771 	qdf_spin_unlock_bh(&soc->ctx_lock);
1772 
1773 #ifdef WMI_INTERFACE_EVENT_LOGGING
1774 	if (wmi_handle->log_info.wmi_logging_enable) {
1775 		uint8_t *data;
1776 		data = qdf_nbuf_data(evt_buf);
1777 
1778 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
1779 		/* Exclude 4 bytes of TLV header */
1780 		WMI_RX_EVENT_RECORD(wmi_handle, id, data +
1781 				wmi_handle->log_info.buf_offset_event);
1782 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
1783 	}
1784 #endif
1785 
1786 	if (exec_ctx == WMI_RX_WORK_CTX) {
1787 		wmi_process_fw_event_worker_thread_ctx
1788 					(wmi_handle, htc_packet);
1789 	} else if (exec_ctx > WMI_RX_WORK_CTX) {
1790 		wmi_process_fw_event_default_ctx
1791 					(wmi_handle, htc_packet, exec_ctx);
1792 	} else {
1793 		qdf_print("%s :Invalid event context %d\n", __func__, exec_ctx);
1794 		qdf_nbuf_free(evt_buf);
1795 	}
1796 
1797 }
1798 
1799 /**
1800  * wmi_process_fw_event() - process any fw event
1801  * @wmi_handle: wmi handle
1802  * @evt_buf: fw event buffer
1803  *
1804  * This function process fw event in caller context
1805  *
1806  * Return: none
1807  */
1808 void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf)
1809 {
1810 	__wmi_control_rx(wmi_handle, evt_buf);
1811 }
1812 
1813 /**
1814  * __wmi_control_rx() - process serialize wmi event callback
1815  * @wmi_handle: wmi handle
1816  * @evt_buf: fw event buffer
1817  *
1818  * Return: none
1819  */
1820 void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf)
1821 {
1822 	uint32_t id;
1823 	uint8_t *data;
1824 	uint32_t len;
1825 	void *wmi_cmd_struct_ptr = NULL;
1826 #ifndef WMI_NON_TLV_SUPPORT
1827 	int tlv_ok_status = 0;
1828 #endif
1829 	uint32_t idx = 0;
1830 
1831 	id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
1832 
1833 	if (qdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL)
1834 		goto end;
1835 
1836 	data = qdf_nbuf_data(evt_buf);
1837 	len = qdf_nbuf_len(evt_buf);
1838 
1839 #ifndef WMI_NON_TLV_SUPPORT
1840 	if (wmi_handle->target_type == WMI_TLV_TARGET) {
1841 		/* Validate and pad(if necessary) the TLVs */
1842 		tlv_ok_status =
1843 			wmi_handle->ops->wmi_check_and_pad_event(wmi_handle->scn_handle,
1844 							data, len, id,
1845 							&wmi_cmd_struct_ptr);
1846 		if (tlv_ok_status != 0) {
1847 			QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1848 				"%s: Error: id=0x%d, wmitlv check status=%d\n",
1849 				__func__, id, tlv_ok_status);
1850 			goto end;
1851 		}
1852 	}
1853 #endif
1854 
1855 	idx = wmi_unified_get_event_handler_ix(wmi_handle, id);
1856 	if (idx == A_ERROR) {
1857 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1858 		   "%s : event handler is not registered: event id 0x%x\n",
1859 			__func__, id);
1860 		goto end;
1861 	}
1862 #ifdef WMI_INTERFACE_EVENT_LOGGING
1863 	if (wmi_handle->log_info.wmi_logging_enable) {
1864 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
1865 		/* Exclude 4 bytes of TLV header */
1866 		if (wmi_handle->ops->is_management_record(id)) {
1867 			WMI_MGMT_EVENT_RECORD(wmi_handle, id, data
1868 				+ wmi_handle->log_info.buf_offset_event);
1869 		} else {
1870 			WMI_EVENT_RECORD(wmi_handle, id, data +
1871 					wmi_handle->log_info.buf_offset_event);
1872 		}
1873 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
1874 	}
1875 #endif
1876 	/* Call the WMI registered event handler */
1877 	if (wmi_handle->target_type == WMI_TLV_TARGET)
1878 		wmi_handle->event_handler[idx] (wmi_handle->scn_handle,
1879 			wmi_cmd_struct_ptr, len);
1880 	else
1881 		wmi_handle->event_handler[idx] (wmi_handle->scn_handle,
1882 			data, len);
1883 
1884 end:
1885 	/* Free event buffer and allocated event tlv */
1886 #ifndef WMI_NON_TLV_SUPPORT
1887 	if (wmi_handle->target_type == WMI_TLV_TARGET)
1888 		wmi_handle->ops->wmi_free_allocated_event(id, &wmi_cmd_struct_ptr);
1889 #endif
1890 
1891 	qdf_nbuf_free(evt_buf);
1892 
1893 }
1894 
1895 #define WMI_WQ_WD_TIMEOUT (30 * 1000) /* 30s */
1896 
1897 static inline void wmi_workqueue_watchdog_warn(uint32_t msg_type_id)
1898 {
1899 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
1900 		  "%s: WLAN_BUG_RCA: Message type %x has exceeded its alloted time of %ds",
1901 		  __func__, msg_type_id, WMI_WQ_WD_TIMEOUT / 1000);
1902 }
1903 
1904 #ifdef CONFIG_SLUB_DEBUG_ON
1905 static void wmi_workqueue_watchdog_bite(void *arg)
1906 {
1907 	struct wmi_wq_dbg_info *info = arg;
1908 
1909 	wmi_workqueue_watchdog_warn(info->wd_msg_type_id);
1910 	qdf_print_thread_trace(info->task);
1911 
1912 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
1913 		  "%s: Going down for WMI WQ Watchdog Bite!", __func__);
1914 	QDF_BUG(0);
1915 }
1916 #else
1917 static inline void wmi_workqueue_watchdog_bite(void *arg)
1918 {
1919 	struct wmi_wq_dbg_info *info = arg;
1920 
1921 	wmi_workqueue_watchdog_warn(info->wd_msg_type_id);
1922 }
1923 #endif
1924 
1925 /**
1926  * wmi_rx_event_work() - process rx event in rx work queue context
1927  * @arg: opaque pointer to wmi handle
1928  *
1929  * This function process any fw event to serialize it through rx worker thread.
1930  *
1931  * Return: none
1932  */
1933 static void wmi_rx_event_work(void *arg)
1934 {
1935 	wmi_buf_t buf;
1936 	struct wmi_unified *wmi = arg;
1937 	qdf_timer_t wd_timer;
1938 	struct wmi_wq_dbg_info info;
1939 
1940 	/* initialize WMI workqueue watchdog timer */
1941 	qdf_timer_init(NULL, &wd_timer, &wmi_workqueue_watchdog_bite,
1942 			&info, QDF_TIMER_TYPE_SW);
1943 	qdf_spin_lock_bh(&wmi->eventq_lock);
1944 	buf = qdf_nbuf_queue_remove(&wmi->event_queue);
1945 	qdf_spin_unlock_bh(&wmi->eventq_lock);
1946 	while (buf) {
1947 		qdf_timer_start(&wd_timer, WMI_WQ_WD_TIMEOUT);
1948 		info.wd_msg_type_id =
1949 		   WMI_GET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID);
1950 		info.wmi_wq = wmi->wmi_rx_work_queue;
1951 		info.task = qdf_get_current_task();
1952 		__wmi_control_rx(wmi, buf);
1953 		qdf_timer_stop(&wd_timer);
1954 		qdf_spin_lock_bh(&wmi->eventq_lock);
1955 		buf = qdf_nbuf_queue_remove(&wmi->event_queue);
1956 		qdf_spin_unlock_bh(&wmi->eventq_lock);
1957 	}
1958 	qdf_timer_free(&wd_timer);
1959 }
1960 
1961 #ifdef FEATURE_RUNTIME_PM
1962 /**
1963  * wmi_runtime_pm_init() - initialize runtime pm wmi variables
1964  * @wmi_handle: wmi context
1965  */
1966 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle)
1967 {
1968 	qdf_atomic_init(&wmi_handle->runtime_pm_inprogress);
1969 }
1970 
1971 /**
1972  * wmi_set_runtime_pm_inprogress() - set runtime pm progress flag
1973  * @wmi_handle: wmi context
1974  * @val: runtime pm progress flag
1975  */
1976 void wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, A_BOOL val)
1977 {
1978 	qdf_atomic_set(&wmi_handle->runtime_pm_inprogress, val);
1979 }
1980 
1981 /**
1982  * wmi_get_runtime_pm_inprogress() - get runtime pm progress flag
1983  * @wmi_handle: wmi context
1984  */
1985 inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle)
1986 {
1987 	return qdf_atomic_read(&wmi_handle->runtime_pm_inprogress);
1988 }
1989 #else
1990 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle)
1991 {
1992 }
1993 #endif
1994 
1995 /**
1996  * wmi_unified_get_soc_handle: Get WMI SoC handle
1997  * @param wmi_handle: WMI context got from wmi_attach
1998  *
1999  * return: Pointer to Soc handle
2000  */
2001 void *wmi_unified_get_soc_handle(struct wmi_unified *wmi_handle)
2002 {
2003 	return wmi_handle->soc;
2004 }
2005 
2006 /**
2007  * wmi_interface_logging_init: Interface looging init
2008  * @param wmi_handle: Pointer to wmi handle object
2009  *
2010  * return: None
2011  */
2012 #ifdef WMI_INTERFACE_EVENT_LOGGING
2013 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle)
2014 {
2015 	if (QDF_STATUS_SUCCESS == wmi_log_init(wmi_handle)) {
2016 		qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock);
2017 		wmi_debugfs_init(wmi_handle);
2018 	}
2019 }
2020 #else
2021 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle)
2022 {
2023 }
2024 #endif
2025 
2026 /**
2027  * wmi_target_params_init: Target specific params init
2028  * @param wmi_soc: Pointer to wmi soc object
2029  * @param wmi_handle: Pointer to wmi handle object
2030  *
2031  * return: None
2032  */
2033 #ifndef CONFIG_MCL
2034 static inline void wmi_target_params_init(struct wmi_soc *soc,
2035 				struct wmi_unified *wmi_handle)
2036 {
2037 	wmi_handle->pdev_param = soc->pdev_param;
2038 	wmi_handle->vdev_param = soc->vdev_param;
2039 	wmi_handle->services = soc->services;
2040 }
2041 #else
2042 static inline void wmi_target_params_init(struct wmi_soc *soc,
2043 				struct wmi_unified *wmi_handle)
2044 {
2045 	wmi_handle->services = soc->services;
2046 }
2047 #endif
2048 
2049 /**
2050  * wmi_unified_get_pdev_handle: Get WMI SoC handle
2051  * @param wmi_soc: Pointer to wmi soc object
2052  * @param pdev_idx: pdev index
2053  *
2054  * return: Pointer to wmi handle or NULL on failure
2055  */
2056 void *wmi_unified_get_pdev_handle(struct wmi_soc *soc, uint32_t pdev_idx)
2057 {
2058 	struct wmi_unified *wmi_handle;
2059 
2060 	if (pdev_idx >= WMI_MAX_RADIOS)
2061 		return NULL;
2062 
2063 	if (soc->wmi_pdev[pdev_idx] == NULL) {
2064 		wmi_handle =
2065 			(struct wmi_unified *) qdf_mem_malloc(
2066 					sizeof(struct wmi_unified));
2067 		if (wmi_handle == NULL) {
2068 			qdf_print("allocation of wmi handle failed %zu\n",
2069 					sizeof(struct wmi_unified));
2070 			return NULL;
2071 		}
2072 		wmi_handle->scn_handle = soc->scn_handle;
2073 		wmi_handle->event_id = soc->event_id;
2074 		wmi_handle->event_handler = soc->event_handler;
2075 		wmi_handle->ctx = soc->ctx;
2076 		wmi_handle->ops = soc->ops;
2077 		qdf_spinlock_create(&wmi_handle->eventq_lock);
2078 		qdf_nbuf_queue_init(&wmi_handle->event_queue);
2079 
2080 		qdf_create_work(0, &wmi_handle->rx_event_work,
2081 				wmi_rx_event_work, wmi_handle);
2082 		wmi_handle->wmi_rx_work_queue =
2083 			qdf_create_workqueue("wmi_rx_event_work_queue");
2084 		if (NULL == wmi_handle->wmi_rx_work_queue) {
2085 			WMI_LOGE("failed to create wmi_rx_event_work_queue");
2086 			goto error;
2087 		}
2088 		wmi_handle->wmi_events = soc->wmi_events;
2089 		wmi_target_params_init(soc, wmi_handle);
2090 		wmi_interface_logging_init(wmi_handle);
2091 		qdf_atomic_init(&wmi_handle->pending_cmds);
2092 		qdf_atomic_init(&wmi_handle->is_target_suspended);
2093 		wmi_handle->target_type = soc->target_type;
2094 		wmi_handle->wmi_max_cmds = soc->wmi_max_cmds;
2095 		wmi_handle->soc = soc;
2096 
2097 		soc->wmi_pdev[pdev_idx] = wmi_handle;
2098 	} else
2099 		wmi_handle = soc->wmi_pdev[pdev_idx];
2100 
2101 	wmi_handle->wmi_stopinprogress = 0;
2102 	wmi_handle->wmi_endpoint_id = soc->wmi_endpoint_id[pdev_idx];
2103 	wmi_handle->htc_handle = soc->htc_handle;
2104 	wmi_handle->max_msg_len = soc->max_msg_len[pdev_idx];
2105 
2106 	return wmi_handle;
2107 
2108 error:
2109 	qdf_mem_free(wmi_handle);
2110 
2111 	return NULL;
2112 }
2113 qdf_export_symbol(wmi_unified_get_pdev_handle);
2114 
2115 static void (*wmi_attach_register[WMI_MAX_TARGET_TYPE])(wmi_unified_t);
2116 
2117 void wmi_unified_register_module(enum wmi_target_type target_type,
2118 			void (*wmi_attach)(wmi_unified_t wmi_handle))
2119 {
2120 	if (target_type < WMI_MAX_TARGET_TYPE)
2121 		wmi_attach_register[target_type] = wmi_attach;
2122 
2123 	return;
2124 }
2125 qdf_export_symbol(wmi_unified_register_module);
2126 
2127 /**
2128  * wmi_unified_attach() -  attach for unified WMI
2129  * @scn_handle: handle to SCN
2130  * @osdev: OS device context
2131  * @target_type: TLV or not-TLV based target
2132  * @use_cookie: cookie based allocation enabled/disabled
2133  * @ops: umac rx callbacks
2134  * @psoc: objmgr psoc
2135  *
2136  * @Return: wmi handle.
2137  */
2138 void *wmi_unified_attach(void *scn_handle,
2139 			 struct wmi_unified_attach_params *param)
2140 {
2141 	struct wmi_unified *wmi_handle;
2142 	struct wmi_soc *soc;
2143 
2144 	soc = (struct wmi_soc *) qdf_mem_malloc(sizeof(struct wmi_soc));
2145 	if (soc == NULL) {
2146 		qdf_print("Allocation of wmi_soc failed %zu\n",
2147 				sizeof(struct wmi_soc));
2148 		return NULL;
2149 	}
2150 
2151 	wmi_handle =
2152 		(struct wmi_unified *) qdf_mem_malloc(
2153 			sizeof(struct wmi_unified));
2154 	if (wmi_handle == NULL) {
2155 		qdf_mem_free(soc);
2156 		qdf_print("allocation of wmi handle failed %zu\n",
2157 			sizeof(struct wmi_unified));
2158 		return NULL;
2159 	}
2160 	wmi_handle->soc = soc;
2161 	wmi_handle->event_id = soc->event_id;
2162 	wmi_handle->event_handler = soc->event_handler;
2163 	wmi_handle->ctx = soc->ctx;
2164 	wmi_handle->wmi_events = soc->wmi_events;
2165 	wmi_target_params_init(soc, wmi_handle);
2166 	wmi_handle->scn_handle = scn_handle;
2167 	soc->scn_handle = scn_handle;
2168 	qdf_atomic_init(&wmi_handle->pending_cmds);
2169 	qdf_atomic_init(&wmi_handle->is_target_suspended);
2170 	wmi_runtime_pm_init(wmi_handle);
2171 	qdf_spinlock_create(&wmi_handle->eventq_lock);
2172 	qdf_nbuf_queue_init(&wmi_handle->event_queue);
2173 	qdf_create_work(0, &wmi_handle->rx_event_work,
2174 			wmi_rx_event_work, wmi_handle);
2175 	wmi_handle->wmi_rx_work_queue =
2176 		qdf_create_workqueue("wmi_rx_event_work_queue");
2177 	if (NULL == wmi_handle->wmi_rx_work_queue) {
2178 		WMI_LOGE("failed to create wmi_rx_event_work_queue");
2179 		goto error;
2180 	}
2181 	wmi_interface_logging_init(wmi_handle);
2182 	/* Attach mc_thread context processing function */
2183 	wmi_handle->rx_ops.wma_process_fw_event_handler_cbk =
2184 				param->rx_ops->wma_process_fw_event_handler_cbk;
2185 	wmi_handle->target_type = param->target_type;
2186 	soc->target_type = param->target_type;
2187 
2188 	if (param->target_type >= WMI_MAX_TARGET_TYPE)
2189 		goto error;
2190 
2191 	if (wmi_attach_register[param->target_type]) {
2192 		wmi_attach_register[param->target_type](wmi_handle);
2193 	} else {
2194 		WMI_LOGE("wmi attach is not registered");
2195 		goto error;
2196 	}
2197 	/* Assign target cookie capablity */
2198 	wmi_handle->use_cookie = param->use_cookie;
2199 	wmi_handle->osdev = param->osdev;
2200 	wmi_handle->wmi_stopinprogress = 0;
2201 	wmi_handle->wmi_max_cmds = param->max_commands;
2202 	soc->wmi_max_cmds = param->max_commands;
2203 	/* Increase the ref count once refcount infra is present */
2204 	soc->wmi_psoc = param->psoc;
2205 	qdf_spinlock_create(&soc->ctx_lock);
2206 
2207 	soc->ops = wmi_handle->ops;
2208 	soc->wmi_pdev[0] = wmi_handle;
2209 
2210 	return wmi_handle;
2211 
2212 error:
2213 	qdf_mem_free(soc);
2214 	qdf_mem_free(wmi_handle);
2215 
2216 	return NULL;
2217 }
2218 
2219 /**
2220  * wmi_unified_detach() -  detach for unified WMI
2221  *
2222  * @wmi_handle  : handle to wmi.
2223  *
2224  * @Return: none.
2225  */
2226 void wmi_unified_detach(struct wmi_unified *wmi_handle)
2227 {
2228 	wmi_buf_t buf;
2229 	struct wmi_soc *soc;
2230 	uint8_t i;
2231 
2232 	soc = wmi_handle->soc;
2233 	for (i = 0; i < WMI_MAX_RADIOS; i++) {
2234 		if (soc->wmi_pdev[i]) {
2235 			qdf_flush_workqueue(0,
2236 				soc->wmi_pdev[i]->wmi_rx_work_queue);
2237 			qdf_destroy_workqueue(0,
2238 				soc->wmi_pdev[i]->wmi_rx_work_queue);
2239 			wmi_debugfs_remove(soc->wmi_pdev[i]);
2240 			buf = qdf_nbuf_queue_remove(
2241 					&soc->wmi_pdev[i]->event_queue);
2242 			while (buf) {
2243 				qdf_nbuf_free(buf);
2244 				buf = qdf_nbuf_queue_remove(
2245 						&soc->wmi_pdev[i]->event_queue);
2246 			}
2247 
2248 			wmi_log_buffer_free(soc->wmi_pdev[i]);
2249 
2250 			/* Free events logs list */
2251 			if (soc->wmi_pdev[i]->events_logs_list)
2252 				qdf_mem_free(
2253 					soc->wmi_pdev[i]->events_logs_list);
2254 
2255 			qdf_spinlock_destroy(&soc->wmi_pdev[i]->eventq_lock);
2256 			qdf_mem_free(soc->wmi_pdev[i]);
2257 		}
2258 	}
2259 	qdf_spinlock_destroy(&soc->ctx_lock);
2260 
2261 	if (soc->wmi_service_bitmap) {
2262 		qdf_mem_free(soc->wmi_service_bitmap);
2263 		soc->wmi_service_bitmap = NULL;
2264 	}
2265 
2266 	if (soc->wmi_ext_service_bitmap) {
2267 		qdf_mem_free(soc->wmi_ext_service_bitmap);
2268 		soc->wmi_ext_service_bitmap = NULL;
2269 	}
2270 
2271 	/* Decrease the ref count once refcount infra is present */
2272 	soc->wmi_psoc = NULL;
2273 	qdf_mem_free(soc);
2274 }
2275 
2276 /**
2277  * wmi_unified_remove_work() - detach for WMI work
2278  * @wmi_handle: handle to WMI
2279  *
2280  * A function that does not fully detach WMI, but just remove work
2281  * queue items associated with it. This is used to make sure that
2282  * before any other processing code that may destroy related contexts
2283  * (HTC, etc), work queue processing on WMI has already been stopped.
2284  *
2285  * Return: None
2286  */
2287 void
2288 wmi_unified_remove_work(struct wmi_unified *wmi_handle)
2289 {
2290 	wmi_buf_t buf;
2291 
2292 	qdf_flush_workqueue(0, wmi_handle->wmi_rx_work_queue);
2293 	qdf_spin_lock_bh(&wmi_handle->eventq_lock);
2294 	buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue);
2295 	while (buf) {
2296 		qdf_nbuf_free(buf);
2297 		buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue);
2298 	}
2299 	qdf_spin_unlock_bh(&wmi_handle->eventq_lock);
2300 }
2301 
2302 /**
2303  * wmi_htc_tx_complete() - Process htc tx completion
2304  *
2305  * @ctx: handle to wmi
2306  * @htc_packet: pointer to htc packet
2307  *
2308  * @Return: none.
2309  */
2310 static void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt)
2311 {
2312 	struct wmi_soc *soc = (struct wmi_soc *) ctx;
2313 	wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt);
2314 	u_int8_t *buf_ptr;
2315 	u_int32_t len;
2316 	struct wmi_unified *wmi_handle;
2317 #ifdef WMI_INTERFACE_EVENT_LOGGING
2318 	uint32_t cmd_id;
2319 #endif
2320 
2321 	ASSERT(wmi_cmd_buf);
2322 	wmi_handle = wmi_get_pdev_ep(soc, htc_pkt->Endpoint);
2323 	if (wmi_handle == NULL) {
2324 		WMI_LOGE("%s: Unable to get wmi handle\n", __func__);
2325 		QDF_ASSERT(0);
2326 		return;
2327 	}
2328 #ifdef WMI_INTERFACE_EVENT_LOGGING
2329 	if (wmi_handle && wmi_handle->log_info.wmi_logging_enable) {
2330 		cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf),
2331 				WMI_CMD_HDR, COMMANDID);
2332 
2333 	qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
2334 	/* Record 16 bytes of WMI cmd tx complete data
2335 	- exclude TLV and WMI headers */
2336 	if (wmi_handle->ops->is_management_record(cmd_id)) {
2337 		WMI_MGMT_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
2338 			qdf_nbuf_data(wmi_cmd_buf) +
2339 			wmi_handle->log_info.buf_offset_command);
2340 	} else {
2341 		WMI_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
2342 			qdf_nbuf_data(wmi_cmd_buf) +
2343 			wmi_handle->log_info.buf_offset_command);
2344 	}
2345 
2346 	qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
2347 	}
2348 #endif
2349 	buf_ptr = (u_int8_t *) wmi_buf_data(wmi_cmd_buf);
2350 	len = qdf_nbuf_len(wmi_cmd_buf);
2351 	qdf_mem_zero(buf_ptr, len);
2352 	qdf_nbuf_free(wmi_cmd_buf);
2353 	qdf_mem_free(htc_pkt);
2354 	qdf_atomic_dec(&wmi_handle->pending_cmds);
2355 }
2356 
2357 /**
2358  * wmi_connect_pdev_htc_service() -  WMI API to get connect to HTC service
2359  *
2360  * @wmi_handle: handle to WMI.
2361  * @pdev_idx: Pdev index
2362  *
2363  * @Return: status.
2364  */
2365 static int wmi_connect_pdev_htc_service(struct wmi_soc *soc,
2366 						uint32_t pdev_idx)
2367 {
2368 	int status;
2369 	struct htc_service_connect_resp response;
2370 	struct htc_service_connect_req connect;
2371 
2372 	OS_MEMZERO(&connect, sizeof(connect));
2373 	OS_MEMZERO(&response, sizeof(response));
2374 
2375 	/* meta data is unused for now */
2376 	connect.pMetaData = NULL;
2377 	connect.MetaDataLength = 0;
2378 	/* these fields are the same for all service endpoints */
2379 	connect.EpCallbacks.pContext = soc;
2380 	connect.EpCallbacks.EpTxCompleteMultiple =
2381 		NULL /* Control path completion ar6000_tx_complete */;
2382 	connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */;
2383 	connect.EpCallbacks.EpRecvRefill = NULL /* ar6000_rx_refill */;
2384 	connect.EpCallbacks.EpSendFull = NULL /* ar6000_tx_queue_full */;
2385 	connect.EpCallbacks.EpTxComplete =
2386 		wmi_htc_tx_complete /* ar6000_tx_queue_full */;
2387 
2388 	/* connect to control service */
2389 	connect.service_id = soc->svc_ids[pdev_idx];
2390 	status = htc_connect_service(soc->htc_handle, &connect,
2391 				&response);
2392 
2393 
2394 	if (status != EOK) {
2395 		qdf_print
2396 			("Failed to connect to WMI CONTROL service status:%d\n",
2397 			status);
2398 		return status;
2399 	}
2400 
2401 	soc->wmi_endpoint_id[pdev_idx] = response.Endpoint;
2402 	soc->max_msg_len[pdev_idx] = response.MaxMsgLength;
2403 
2404 	return 0;
2405 }
2406 
2407 /**
2408  * wmi_unified_connect_htc_service() -  WMI API to get connect to HTC service
2409  *
2410  * @wmi_handle: handle to WMI.
2411  *
2412  * @Return: status.
2413  */
2414 QDF_STATUS
2415 wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle,
2416 				void *htc_handle)
2417 {
2418 	uint32_t i;
2419 	uint8_t wmi_ep_count;
2420 
2421 	wmi_handle->soc->htc_handle = htc_handle;
2422 
2423 	wmi_ep_count = htc_get_wmi_endpoint_count(htc_handle);
2424 	if (wmi_ep_count > WMI_MAX_RADIOS)
2425 		return QDF_STATUS_E_FAULT;
2426 
2427 	for (i = 0; i < wmi_ep_count; i++)
2428 		wmi_connect_pdev_htc_service(wmi_handle->soc, i);
2429 
2430 	wmi_handle->htc_handle = htc_handle;
2431 	wmi_handle->wmi_endpoint_id = wmi_handle->soc->wmi_endpoint_id[0];
2432 	wmi_handle->max_msg_len = wmi_handle->soc->max_msg_len[0];
2433 
2434 	return QDF_STATUS_SUCCESS;
2435 }
2436 
2437 /**
2438  * wmi_get_host_credits() -  WMI API to get updated host_credits
2439  *
2440  * @wmi_handle: handle to WMI.
2441  *
2442  * @Return: updated host_credits.
2443  */
2444 int wmi_get_host_credits(wmi_unified_t wmi_handle)
2445 {
2446 	int host_credits = 0;
2447 
2448 	htc_get_control_endpoint_tx_host_credits(wmi_handle->htc_handle,
2449 						 &host_credits);
2450 	return host_credits;
2451 }
2452 
2453 /**
2454  * wmi_get_pending_cmds() - WMI API to get WMI Pending Commands in the HTC
2455  *                          queue
2456  *
2457  * @wmi_handle: handle to WMI.
2458  *
2459  * @Return: Pending Commands in the HTC queue.
2460  */
2461 int wmi_get_pending_cmds(wmi_unified_t wmi_handle)
2462 {
2463 	return qdf_atomic_read(&wmi_handle->pending_cmds);
2464 }
2465 
2466 /**
2467  * wmi_set_target_suspend() -  WMI API to set target suspend state
2468  *
2469  * @wmi_handle: handle to WMI.
2470  * @val: suspend state boolean.
2471  *
2472  * @Return: none.
2473  */
2474 void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val)
2475 {
2476 	qdf_atomic_set(&wmi_handle->is_target_suspended, val);
2477 }
2478 
2479 /**
2480  * WMI API to set crash injection state
2481  * @param wmi_handle:	handle to WMI.
2482  * @param val:		crash injection state boolean.
2483  */
2484 void wmi_tag_crash_inject(wmi_unified_t wmi_handle, A_BOOL flag)
2485 {
2486 	wmi_handle->tag_crash_inject = flag;
2487 }
2488 
2489 /**
2490  * WMI API to set bus suspend state
2491  * @param wmi_handle:	handle to WMI.
2492  * @param val:		suspend state boolean.
2493  */
2494 void wmi_set_is_wow_bus_suspended(wmi_unified_t wmi_handle, A_BOOL val)
2495 {
2496 	qdf_atomic_set(&wmi_handle->is_wow_bus_suspended, val);
2497 }
2498 
2499 void wmi_set_tgt_assert(wmi_unified_t wmi_handle, bool val)
2500 {
2501 	wmi_handle->tgt_force_assert_enable = val;
2502 }
2503 
2504 /**
2505  * wmi_stop() - generic function to block unified WMI command
2506  * @wmi_handle: handle to WMI.
2507  *
2508  * @Return: success always.
2509  */
2510 int
2511 wmi_stop(wmi_unified_t wmi_handle)
2512 {
2513 	QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO,
2514 		  "WMI Stop\n");
2515 	wmi_handle->wmi_stopinprogress = 1;
2516 	return 0;
2517 }
2518 
2519 #ifndef CONFIG_MCL
2520 /**
2521  * API to flush all the previous packets  associated with the wmi endpoint
2522  *
2523  * @param wmi_handle      : handle to WMI.
2524  */
2525 void
2526 wmi_flush_endpoint(wmi_unified_t wmi_handle)
2527 {
2528 	htc_flush_endpoint(wmi_handle->htc_handle,
2529 		wmi_handle->wmi_endpoint_id, 0);
2530 }
2531 qdf_export_symbol(wmi_flush_endpoint);
2532 
2533 /**
2534  * wmi_pdev_id_conversion_enable() - API to enable pdev_id conversion in WMI
2535  *                     By default pdev_id conversion is not done in WMI.
2536  *                     This API can be used enable conversion in WMI.
2537  * @param wmi_handle   : handle to WMI
2538  * Return none
2539  */
2540 void wmi_pdev_id_conversion_enable(wmi_unified_t wmi_handle)
2541 {
2542 	if (wmi_handle->target_type == WMI_TLV_TARGET)
2543 		wmi_handle->ops->wmi_pdev_id_conversion_enable(wmi_handle);
2544 }
2545 
2546 #endif
2547