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