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