xref: /wlan-dirver/qca-wifi-host-cmn/wmi/src/wmi_unified.c (revision 503663c6daafffe652fa360bde17243568cd6d2a)
1 /*
2  * Copyright (c) 2015-2020 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 #include "qdf_platform.h"
28 #ifdef WMI_EXT_DBG
29 #include "qdf_list.h"
30 #include "qdf_atomic.h"
31 #endif
32 
33 #ifndef WMI_NON_TLV_SUPPORT
34 #include "wmi_tlv_helper.h"
35 #endif
36 
37 #include <linux/debugfs.h>
38 #include <target_if.h>
39 
40 /* This check for CONFIG_WIN temporary added due to redeclaration compilation
41 error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h
42 which gets included here through ol_if_athvar.h. Eventually it is expected that
43 wmi.h will be removed from wmi_unified_api.h after cleanup, which will need
44 WMI_CMD_HDR to be defined here. */
45 /* Copied from wmi.h */
46 #undef MS
47 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
48 #undef SM
49 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
50 #undef WO
51 #define WO(_f)      ((_f##_OFFSET) >> 2)
52 
53 #undef GET_FIELD
54 #define GET_FIELD(_addr, _f) MS(*((uint32_t *)(_addr) + WO(_f)), _f)
55 #undef SET_FIELD
56 #define SET_FIELD(_addr, _f, _val)  \
57 	    (*((uint32_t *)(_addr) + WO(_f)) = \
58 		(*((uint32_t *)(_addr) + WO(_f)) & ~_f##_MASK) | SM(_val, _f))
59 
60 #define WMI_GET_FIELD(_msg_buf, _msg_type, _f) \
61 	    GET_FIELD(_msg_buf, _msg_type ## _ ## _f)
62 
63 #define WMI_SET_FIELD(_msg_buf, _msg_type, _f, _val) \
64 	    SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val)
65 
66 #define WMI_EP_APASS           0x0
67 #define WMI_EP_LPASS           0x1
68 #define WMI_EP_SENSOR          0x2
69 
70 /*
71  *  * Control Path
72  *   */
73 typedef PREPACK struct {
74 	uint32_t	commandId:24,
75 			reserved:2, /* used for WMI endpoint ID */
76 			plt_priv:6; /* platform private */
77 } POSTPACK WMI_CMD_HDR;        /* used for commands and events */
78 
79 #define WMI_CMD_HDR_COMMANDID_LSB           0
80 #define WMI_CMD_HDR_COMMANDID_MASK          0x00ffffff
81 #define WMI_CMD_HDR_COMMANDID_OFFSET        0x00000000
82 #define WMI_CMD_HDR_WMI_ENDPOINTID_MASK        0x03000000
83 #define WMI_CMD_HDR_WMI_ENDPOINTID_OFFSET      24
84 #define WMI_CMD_HDR_PLT_PRIV_LSB               24
85 #define WMI_CMD_HDR_PLT_PRIV_MASK              0xff000000
86 #define WMI_CMD_HDR_PLT_PRIV_OFFSET            0x00000000
87 /* end of copy wmi.h */
88 
89 #define WMI_MIN_HEAD_ROOM 64
90 
91 /* WBUFF pool sizes for WMI */
92 /* Allocation of size 256 bytes */
93 #define WMI_WBUFF_POOL_0_SIZE 128
94 /* Allocation of size 512 bytes */
95 #define WMI_WBUFF_POOL_1_SIZE 16
96 /* Allocation of size 1024 bytes */
97 #define WMI_WBUFF_POOL_2_SIZE 8
98 /* Allocation of size 2048 bytes */
99 #define WMI_WBUFF_POOL_3_SIZE 8
100 
101 #ifdef WMI_INTERFACE_EVENT_LOGGING
102 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0))
103 /* TODO Cleanup this backported function */
104 static int wmi_bp_seq_printf(struct seq_file *m, const char *f, ...)
105 {
106 	va_list args;
107 
108 	va_start(args, f);
109 	seq_vprintf(m, f, args);
110 	va_end(args);
111 
112 	return 0;
113 }
114 #else
115 #define wmi_bp_seq_printf(m, fmt, ...) seq_printf((m), fmt, ##__VA_ARGS__)
116 #endif
117 
118 #ifndef MAX_WMI_INSTANCES
119 #define CUSTOM_MGMT_CMD_DATA_SIZE 4
120 #endif
121 
122 #ifndef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC
123 /* WMI commands */
124 uint32_t g_wmi_command_buf_idx = 0;
125 struct wmi_command_debug wmi_command_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
126 
127 /* WMI commands TX completed */
128 uint32_t g_wmi_command_tx_cmp_buf_idx = 0;
129 struct wmi_command_debug
130 	wmi_command_tx_cmp_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
131 
132 /* WMI events when processed */
133 uint32_t g_wmi_event_buf_idx = 0;
134 struct wmi_event_debug wmi_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
135 
136 /* WMI events when queued */
137 uint32_t g_wmi_rx_event_buf_idx = 0;
138 struct wmi_event_debug wmi_rx_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY];
139 #endif
140 
141 #define WMI_COMMAND_RECORD(h, a, b) {					\
142 	if (wmi_log_max_entry <=					\
143 		*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx))	\
144 		*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx) = 0;\
145 	((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\
146 		[*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)]\
147 						.command = a;		\
148 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.		\
149 				wmi_command_log_buf_info.buf)		\
150 		[*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].data,\
151 			b, wmi_record_max_length);			\
152 	((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\
153 		[*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].\
154 		time = qdf_get_log_timestamp();			\
155 	(*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx))++;	\
156 	h->log_info.wmi_command_log_buf_info.length++;			\
157 }
158 
159 #define WMI_COMMAND_TX_CMP_RECORD(h, a, b) {				\
160 	if (wmi_log_max_entry <=					\
161 		*(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))\
162 		*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
163 				p_buf_tail_idx) = 0;			\
164 	((struct wmi_command_debug *)h->log_info.			\
165 		wmi_command_tx_cmp_log_buf_info.buf)			\
166 		[*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
167 				p_buf_tail_idx)].			\
168 							command	= a;	\
169 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.		\
170 				wmi_command_tx_cmp_log_buf_info.buf)	\
171 		[*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
172 			p_buf_tail_idx)].				\
173 		data, b, wmi_record_max_length);			\
174 	((struct wmi_command_debug *)h->log_info.			\
175 		wmi_command_tx_cmp_log_buf_info.buf)			\
176 		[*(h->log_info.wmi_command_tx_cmp_log_buf_info.		\
177 				p_buf_tail_idx)].			\
178 		time = qdf_get_log_timestamp();				\
179 	(*(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))++;\
180 	h->log_info.wmi_command_tx_cmp_log_buf_info.length++;		\
181 }
182 
183 #define WMI_EVENT_RECORD(h, a, b) {					\
184 	if (wmi_log_max_entry <=					\
185 		*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx))	\
186 		*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx) = 0;\
187 	((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\
188 		[*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].	\
189 		event = a;						\
190 	qdf_mem_copy(((struct wmi_event_debug *)h->log_info.		\
191 				wmi_event_log_buf_info.buf)		\
192 		[*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].data, b,\
193 		wmi_record_max_length);					\
194 	((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\
195 		[*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].time =\
196 		qdf_get_log_timestamp();				\
197 	(*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx))++;	\
198 	h->log_info.wmi_event_log_buf_info.length++;			\
199 }
200 
201 #define WMI_RX_EVENT_RECORD(h, a, b) {					\
202 	if (wmi_log_max_entry <=					\
203 		*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))\
204 		*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx) = 0;\
205 	((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\
206 		[*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\
207 		event = a;						\
208 	qdf_mem_copy(((struct wmi_event_debug *)h->log_info.		\
209 				wmi_rx_event_log_buf_info.buf)		\
210 		[*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\
211 			data, b, wmi_record_max_length);		\
212 	((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\
213 		[*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\
214 		time =	qdf_get_log_timestamp();			\
215 	(*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))++;	\
216 	h->log_info.wmi_rx_event_log_buf_info.length++;			\
217 }
218 
219 #ifndef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC
220 uint32_t g_wmi_mgmt_command_buf_idx = 0;
221 struct
222 wmi_command_debug wmi_mgmt_command_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY];
223 
224 /* wmi_mgmt commands TX completed */
225 uint32_t g_wmi_mgmt_command_tx_cmp_buf_idx = 0;
226 struct wmi_command_debug
227 wmi_mgmt_command_tx_cmp_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY];
228 
229 /* wmi_mgmt events when received */
230 uint32_t g_wmi_mgmt_rx_event_buf_idx = 0;
231 struct wmi_event_debug
232 wmi_mgmt_rx_event_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY];
233 
234 /* wmi_diag events when received */
235 uint32_t g_wmi_diag_rx_event_buf_idx = 0;
236 struct wmi_event_debug
237 wmi_diag_rx_event_log_buffer[WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY];
238 #endif
239 
240 #define WMI_MGMT_COMMAND_RECORD(h, a, b) {                              \
241 	if (wmi_mgmt_log_max_entry <=                                   \
242 		*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)) \
243 		*(h->log_info.wmi_mgmt_command_log_buf_info.		\
244 				p_buf_tail_idx) = 0;			\
245 	((struct wmi_command_debug *)h->log_info.                       \
246 		 wmi_mgmt_command_log_buf_info.buf)                     \
247 		[*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\
248 			command = a;                                    \
249 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.          \
250 				wmi_mgmt_command_log_buf_info.buf)      \
251 		[*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\
252 		data, b,                                                \
253 		wmi_record_max_length);                                	\
254 	((struct wmi_command_debug *)h->log_info.                       \
255 		 wmi_mgmt_command_log_buf_info.buf)                     \
256 		[*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx)].\
257 			time =        qdf_get_log_timestamp();          \
258 	(*(h->log_info.wmi_mgmt_command_log_buf_info.p_buf_tail_idx))++;\
259 	h->log_info.wmi_mgmt_command_log_buf_info.length++;             \
260 }
261 
262 #define WMI_MGMT_COMMAND_TX_CMP_RECORD(h, a, b) {			\
263 	if (wmi_mgmt_log_max_entry <=					\
264 		*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
265 			p_buf_tail_idx))				\
266 		*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
267 			p_buf_tail_idx) = 0;				\
268 	((struct wmi_command_debug *)h->log_info.			\
269 			wmi_mgmt_command_tx_cmp_log_buf_info.buf)	\
270 		[*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
271 				p_buf_tail_idx)].command = a;		\
272 	qdf_mem_copy(((struct wmi_command_debug *)h->log_info.		\
273 				wmi_mgmt_command_tx_cmp_log_buf_info.buf)\
274 		[*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
275 			p_buf_tail_idx)].data, b,			\
276 			wmi_record_max_length);				\
277 	((struct wmi_command_debug *)h->log_info.			\
278 			wmi_mgmt_command_tx_cmp_log_buf_info.buf)	\
279 		[*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.	\
280 				p_buf_tail_idx)].time =			\
281 		qdf_get_log_timestamp();				\
282 	(*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.		\
283 			p_buf_tail_idx))++;				\
284 	h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.length++;	\
285 }
286 
287 #define WMI_MGMT_RX_EVENT_RECORD(h, a, b) do {				\
288 	if (wmi_mgmt_log_max_entry <=					\
289 		*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))\
290 		*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx) = 0;\
291 	((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\
292 		[*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)]\
293 					.event = a;			\
294 	qdf_mem_copy(((struct wmi_event_debug *)h->log_info.		\
295 				wmi_mgmt_event_log_buf_info.buf)	\
296 		[*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\
297 			data, b, wmi_record_max_length);		\
298 	((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\
299 		[*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\
300 			time = qdf_get_log_timestamp();			\
301 	(*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))++;	\
302 	h->log_info.wmi_mgmt_event_log_buf_info.length++;		\
303 } while (0);
304 
305 #define WMI_DIAG_RX_EVENT_RECORD(h, a, b) do {                             \
306 	if (wmi_diag_log_max_entry <=                                   \
307 		*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx))\
308 		*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx) = 0;\
309 	((struct wmi_event_debug *)h->log_info.wmi_diag_event_log_buf_info.buf)\
310 		[*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)]\
311 					.event = a;                     \
312 	qdf_mem_copy(((struct wmi_event_debug *)h->log_info.            \
313 				wmi_diag_event_log_buf_info.buf)        \
314 		[*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)].\
315 			data, b, wmi_record_max_length);                \
316 	((struct wmi_event_debug *)h->log_info.wmi_diag_event_log_buf_info.buf)\
317 		[*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx)].\
318 			time = qdf_get_log_timestamp();                 \
319 	(*(h->log_info.wmi_diag_event_log_buf_info.p_buf_tail_idx))++;  \
320 	h->log_info.wmi_diag_event_log_buf_info.length++;               \
321 } while (0);
322 
323 /* These are defined to made it as module param, which can be configured */
324 uint32_t wmi_log_max_entry = WMI_EVENT_DEBUG_MAX_ENTRY;
325 uint32_t wmi_mgmt_log_max_entry = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
326 uint32_t wmi_diag_log_max_entry = WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY;
327 uint32_t wmi_record_max_length = WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH;
328 uint32_t wmi_display_size = 100;
329 
330 #ifdef WMI_EXT_DBG
331 
332 /**
333  * wmi_ext_dbg_msg_enqueue() - enqueue wmi message
334  *
335  * @wmi_handle: wmi handler
336  *
337  * Return: size of wmi message queue after enqueue
338  */
339 static uint32_t wmi_ext_dbg_msg_enqueue(struct wmi_unified *wmi_handle,
340 					struct wmi_ext_dbg_msg *msg)
341 {
342 	uint32_t list_size;
343 
344 	qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
345 	qdf_list_insert_back_size(&wmi_handle->wmi_ext_dbg_msg_queue,
346 				  &msg->node, &list_size);
347 	qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
348 
349 	return list_size;
350 }
351 
352 /**
353  * wmi_ext_dbg_msg_dequeue() - dequeue wmi message
354  *
355  * @wmi_handle: wmi handler
356  *
357  * Return: wmi msg on success else NULL
358  */
359 static struct wmi_ext_dbg_msg *wmi_ext_dbg_msg_dequeue(struct wmi_unified
360 						       *wmi_handle)
361 {
362 	qdf_list_node_t *list_node = NULL;
363 
364 	qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
365 	qdf_list_remove_front(&wmi_handle->wmi_ext_dbg_msg_queue, &list_node);
366 	qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
367 
368 	if (!list_node)
369 		return NULL;
370 
371 	return qdf_container_of(list_node, struct wmi_ext_dbg_msg, node);
372 }
373 
374 /**
375  * wmi_ext_dbg_msg_record() - record wmi messages
376  *
377  * @wmi_handle: wmi handler
378  * @buf: wmi message buffer
379  * @len: wmi message length
380  * @type: wmi message type
381  *
382  * Return: QDF_STATUS_SUCCESS on successful recording else failure.
383  */
384 static QDF_STATUS wmi_ext_dbg_msg_record(struct wmi_unified *wmi_handle,
385 					 uint8_t *buf, uint32_t len,
386 					 enum WMI_MSG_TYPE type)
387 {
388 	struct wmi_ext_dbg_msg *msg;
389 	uint32_t list_size;
390 
391 	msg = wmi_ext_dbg_msg_get(len);
392 	if (!msg)
393 		return QDF_STATUS_E_NOMEM;
394 
395 	msg->len = len;
396 	msg->type = type;
397 	qdf_mem_copy(msg->buf, buf, len);
398 	msg->ts = qdf_get_log_timestamp();
399 	list_size = wmi_ext_dbg_msg_enqueue(wmi_handle, msg);
400 
401 	if (list_size >= wmi_handle->wmi_ext_dbg_msg_queue_size) {
402 		msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
403 		wmi_ext_dbg_msg_put(msg);
404 	}
405 
406 	return QDF_STATUS_SUCCESS;
407 }
408 
409 /**
410  * wmi_ext_dbg_msg_cmd_record() - record wmi command messages
411  *
412  * @wmi_handle: wmi handler
413  * @buf: wmi command buffer
414  * @len: wmi command message length
415  *
416  * Return: QDF_STATUS_SUCCESS on successful recording else failure.
417  */
418 static QDF_STATUS wmi_ext_dbg_msg_cmd_record(struct wmi_unified *wmi_handle,
419 					     uint8_t *buf, uint32_t len)
420 {
421 	return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
422 				      WMI_MSG_TYPE_CMD);
423 }
424 
425 /**
426  * wmi_ext_dbg_msg_event_record() - record wmi event messages
427  *
428  * @wmi_handle: wmi handler
429  * @buf: wmi event buffer
430  * @len: wmi event message length
431  *
432  * Return: QDF_STATUS_SUCCESS on successful recording else failure.
433  */
434 static QDF_STATUS wmi_ext_dbg_msg_event_record(struct wmi_unified *wmi_handle,
435 					       uint8_t *buf, uint32_t len)
436 {
437 	uint32_t id;
438 
439 	id = WMI_GET_FIELD(buf, WMI_CMD_HDR, COMMANDID);
440 	if (id != wmi_handle->wmi_events[wmi_diag_event_id])
441 		return wmi_ext_dbg_msg_record(wmi_handle, buf, len,
442 					      WMI_MSG_TYPE_EVENT);
443 
444 	return QDF_STATUS_SUCCESS;
445 }
446 
447 /**
448  * wmi_ext_dbg_msg_queue_init() - create debugfs queue and associated lock
449  *
450  * @wmi_handle: wmi handler
451  *
452  * Return: none
453  */
454 static void wmi_ext_dbg_msg_queue_init(struct wmi_unified *wmi_handle)
455 {
456 	qdf_list_create(&wmi_handle->wmi_ext_dbg_msg_queue,
457 			wmi_handle->wmi_ext_dbg_msg_queue_size);
458 	qdf_spinlock_create(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
459 }
460 
461 /**
462  * wmi_ext_dbg_msg_queue_deinit() - destroy debugfs queue and associated lock
463  *
464  * @wmi_handle: wmi handler
465  *
466  * Return: none
467  */
468 static void wmi_ext_dbg_msg_queue_deinit(struct wmi_unified *wmi_handle)
469 {
470 	qdf_list_destroy(&wmi_handle->wmi_ext_dbg_msg_queue);
471 	qdf_spinlock_destroy(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
472 }
473 
474 /**
475  * wmi_ext_dbg_msg_show() - debugfs function to display whole content of
476  * wmi command/event messages including headers.
477  *
478  * @file: qdf debugfs file handler
479  * @arg: pointer to wmi handler
480  *
481  * Return: QDF_STATUS_SUCCESS if all the messages are shown successfully,
482  * else QDF_STATUS_E_AGAIN if more data to show.
483  */
484 static QDF_STATUS wmi_ext_dbg_msg_show(qdf_debugfs_file_t file, void *arg)
485 {
486 	struct wmi_unified *wmi_handle = (struct wmi_unified *)arg;
487 	struct wmi_ext_dbg_msg *msg;
488 	uint64_t secs, usecs;
489 
490 	msg = wmi_ext_dbg_msg_dequeue(wmi_handle);
491 	if (!msg)
492 		return QDF_STATUS_SUCCESS;
493 
494 	qdf_debugfs_printf(file, "%s: 0x%x\n",
495 			   msg->type == WMI_MSG_TYPE_CMD ? "COMMAND" :
496 			   "EVENT", WMI_GET_FIELD(msg->buf, WMI_CMD_HDR,
497 						  COMMANDID));
498 	qdf_log_timestamp_to_secs(msg->ts, &secs, &usecs);
499 	qdf_debugfs_printf(file, "Time: %llu.%llu\n", secs, usecs);
500 	qdf_debugfs_printf(file, "Length:%d\n", msg->len);
501 	qdf_debugfs_hexdump(file, msg->buf, msg->len,
502 			    WMI_EXT_DBG_DUMP_ROW_SIZE,
503 			    WMI_EXT_DBG_DUMP_GROUP_SIZE);
504 	qdf_debugfs_printf(file, "\n");
505 
506 	if (qdf_debugfs_overflow(file)) {
507 		qdf_spinlock_acquire(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
508 		qdf_list_insert_front(&wmi_handle->wmi_ext_dbg_msg_queue,
509 				      &msg->node);
510 		qdf_spinlock_release(&wmi_handle->wmi_ext_dbg_msg_queue_lock);
511 
512 	} else {
513 		wmi_ext_dbg_msg_put(msg);
514 	}
515 
516 	return QDF_STATUS_E_AGAIN;
517 }
518 
519 /**
520  * wmi_ext_dbg_msg_write() - debugfs write not supported
521  *
522  * @priv: private data
523  * @buf: received data buffer
524  * @len: length of received buffer
525  *
526  * Return: QDF_STATUS_E_NOSUPPORT.
527  */
528 static QDF_STATUS wmi_ext_dbg_msg_write(void *priv, const char *buf,
529 					qdf_size_t len)
530 {
531 	return QDF_STATUS_E_NOSUPPORT;
532 }
533 
534 static struct qdf_debugfs_fops wmi_ext_dbgfs_ops = {
535 	.show		= wmi_ext_dbg_msg_show,
536 	.write		= wmi_ext_dbg_msg_write,
537 	.priv		= NULL,
538 };
539 
540 /**
541  * wmi_ext_debugfs_init() - init debugfs items for extended wmi dump.
542  *
543  * @wmi_handle: wmi handler
544  *
545  * Return: QDF_STATUS_SUCCESS if debugfs is initialized else
546  * QDF_STATUS_E_FAILURE
547  */
548 static QDF_STATUS wmi_ext_dbgfs_init(struct wmi_unified *wmi_handle)
549 {
550 	qdf_dentry_t dentry;
551 
552 	dentry  = qdf_debugfs_create_dir(WMI_EXT_DBG_DIR, NULL);
553 	if (!dentry) {
554 		WMI_LOGE("error while creating extended wmi debugfs dir");
555 		return QDF_STATUS_E_FAILURE;
556 	}
557 
558 	wmi_ext_dbgfs_ops.priv = wmi_handle;
559 	if (!qdf_debugfs_create_file(WMI_EXT_DBG_FILE, WMI_EXT_DBG_FILE_PERM,
560 				     dentry, &wmi_ext_dbgfs_ops)) {
561 		qdf_debugfs_remove_dir(dentry);
562 		WMI_LOGE("error while creating extended wmi debugfs file");
563 		return QDF_STATUS_E_FAILURE;
564 	}
565 
566 	wmi_handle->wmi_ext_dbg_dentry = dentry;
567 	wmi_handle->wmi_ext_dbg_msg_queue_size = WMI_EXT_DBG_QUEUE_SIZE;
568 	wmi_ext_dbg_msg_queue_init(wmi_handle);
569 
570 	return QDF_STATUS_SUCCESS;
571 }
572 
573 /**
574  * wmi_ext_debugfs_deinit() - cleanup/deinit debugfs items of extended wmi dump.
575  *
576  * @wmi_handle: wmi handler
577  *
578  * Return: QDF_STATUS_SUCCESS if cleanup is successful
579  */
580 static QDF_STATUS wmi_ext_dbgfs_deinit(struct wmi_unified *wmi_handle)
581 {
582 	struct wmi_ext_dbg_msg *msg;
583 
584 	while ((msg = wmi_ext_dbg_msg_dequeue(wmi_handle)))
585 		wmi_ext_dbg_msg_put(msg);
586 
587 	wmi_ext_dbg_msg_queue_deinit(wmi_handle);
588 	qdf_debugfs_remove_dir_recursive(wmi_handle->wmi_ext_dbg_dentry);
589 
590 	return QDF_STATUS_SUCCESS;
591 }
592 
593 #endif /*WMI_EXT_DBG */
594 
595 /**
596  * wmi_log_init() - Initialize WMI event logging
597  * @wmi_handle: WMI handle.
598  *
599  * Return: Initialization status
600  */
601 #ifndef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC
602 static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle)
603 {
604 	struct wmi_log_buf_t *cmd_log_buf =
605 			&wmi_handle->log_info.wmi_command_log_buf_info;
606 	struct wmi_log_buf_t *cmd_tx_cmpl_log_buf =
607 			&wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info;
608 
609 	struct wmi_log_buf_t *event_log_buf =
610 			&wmi_handle->log_info.wmi_event_log_buf_info;
611 	struct wmi_log_buf_t *rx_event_log_buf =
612 			&wmi_handle->log_info.wmi_rx_event_log_buf_info;
613 
614 	struct wmi_log_buf_t *mgmt_cmd_log_buf =
615 			&wmi_handle->log_info.wmi_mgmt_command_log_buf_info;
616 	struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf =
617 		&wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info;
618 	struct wmi_log_buf_t *mgmt_event_log_buf =
619 			&wmi_handle->log_info.wmi_mgmt_event_log_buf_info;
620 	struct wmi_log_buf_t *diag_event_log_buf =
621 			&wmi_handle->log_info.wmi_diag_event_log_buf_info;
622 
623 	/* WMI commands */
624 	cmd_log_buf->length = 0;
625 	cmd_log_buf->buf_tail_idx = 0;
626 	cmd_log_buf->buf = wmi_command_log_buffer;
627 	cmd_log_buf->p_buf_tail_idx = &g_wmi_command_buf_idx;
628 	cmd_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
629 
630 	/* WMI commands TX completed */
631 	cmd_tx_cmpl_log_buf->length = 0;
632 	cmd_tx_cmpl_log_buf->buf_tail_idx = 0;
633 	cmd_tx_cmpl_log_buf->buf = wmi_command_tx_cmp_log_buffer;
634 	cmd_tx_cmpl_log_buf->p_buf_tail_idx = &g_wmi_command_tx_cmp_buf_idx;
635 	cmd_tx_cmpl_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
636 
637 	/* WMI events when processed */
638 	event_log_buf->length = 0;
639 	event_log_buf->buf_tail_idx = 0;
640 	event_log_buf->buf = wmi_event_log_buffer;
641 	event_log_buf->p_buf_tail_idx = &g_wmi_event_buf_idx;
642 	event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
643 
644 	/* WMI events when queued */
645 	rx_event_log_buf->length = 0;
646 	rx_event_log_buf->buf_tail_idx = 0;
647 	rx_event_log_buf->buf = wmi_rx_event_log_buffer;
648 	rx_event_log_buf->p_buf_tail_idx = &g_wmi_rx_event_buf_idx;
649 	rx_event_log_buf->size = WMI_EVENT_DEBUG_MAX_ENTRY;
650 
651 	/* WMI Management commands */
652 	mgmt_cmd_log_buf->length = 0;
653 	mgmt_cmd_log_buf->buf_tail_idx = 0;
654 	mgmt_cmd_log_buf->buf = wmi_mgmt_command_log_buffer;
655 	mgmt_cmd_log_buf->p_buf_tail_idx = &g_wmi_mgmt_command_buf_idx;
656 	mgmt_cmd_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
657 
658 	/* WMI Management commands Tx completed*/
659 	mgmt_cmd_tx_cmp_log_buf->length = 0;
660 	mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0;
661 	mgmt_cmd_tx_cmp_log_buf->buf = wmi_mgmt_command_tx_cmp_log_buffer;
662 	mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx =
663 		&g_wmi_mgmt_command_tx_cmp_buf_idx;
664 	mgmt_cmd_tx_cmp_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
665 
666 	/* WMI Management events when received */
667 	mgmt_event_log_buf->length = 0;
668 	mgmt_event_log_buf->buf_tail_idx = 0;
669 	mgmt_event_log_buf->buf = wmi_mgmt_rx_event_log_buffer;
670 	mgmt_event_log_buf->p_buf_tail_idx = &g_wmi_mgmt_rx_event_buf_idx;
671 	mgmt_event_log_buf->size = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY;
672 
673 	/* WMI diag events when received */
674 	diag_event_log_buf->length = 0;
675 	diag_event_log_buf->buf_tail_idx = 0;
676 	diag_event_log_buf->buf = wmi_diag_rx_event_log_buffer;
677 	diag_event_log_buf->p_buf_tail_idx = &g_wmi_diag_rx_event_buf_idx;
678 	diag_event_log_buf->size = WMI_DIAG_RX_EVENT_DEBUG_MAX_ENTRY;
679 
680 	qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock);
681 	wmi_handle->log_info.wmi_logging_enable = 1;
682 
683 	return QDF_STATUS_SUCCESS;
684 }
685 #else
686 static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle)
687 {
688 	struct wmi_log_buf_t *cmd_log_buf =
689 			&wmi_handle->log_info.wmi_command_log_buf_info;
690 	struct wmi_log_buf_t *cmd_tx_cmpl_log_buf =
691 			&wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info;
692 
693 	struct wmi_log_buf_t *event_log_buf =
694 			&wmi_handle->log_info.wmi_event_log_buf_info;
695 	struct wmi_log_buf_t *rx_event_log_buf =
696 			&wmi_handle->log_info.wmi_rx_event_log_buf_info;
697 
698 	struct wmi_log_buf_t *mgmt_cmd_log_buf =
699 			&wmi_handle->log_info.wmi_mgmt_command_log_buf_info;
700 	struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf =
701 		&wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info;
702 	struct wmi_log_buf_t *mgmt_event_log_buf =
703 			&wmi_handle->log_info.wmi_mgmt_event_log_buf_info;
704 	struct wmi_log_buf_t *diag_event_log_buf =
705 			&wmi_handle->log_info.wmi_diag_event_log_buf_info;
706 
707 	wmi_handle->log_info.wmi_logging_enable = 0;
708 
709 	/* WMI commands */
710 	cmd_log_buf->length = 0;
711 	cmd_log_buf->buf_tail_idx = 0;
712 	cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc(
713 		wmi_log_max_entry * sizeof(struct wmi_command_debug));
714 	cmd_log_buf->size = wmi_log_max_entry;
715 
716 	if (!cmd_log_buf->buf)
717 		return QDF_STATUS_E_NOMEM;
718 
719 	cmd_log_buf->p_buf_tail_idx = &cmd_log_buf->buf_tail_idx;
720 
721 	/* WMI commands TX completed */
722 	cmd_tx_cmpl_log_buf->length = 0;
723 	cmd_tx_cmpl_log_buf->buf_tail_idx = 0;
724 	cmd_tx_cmpl_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc(
725 		wmi_log_max_entry * sizeof(struct wmi_command_debug));
726 	cmd_tx_cmpl_log_buf->size = wmi_log_max_entry;
727 
728 	if (!cmd_tx_cmpl_log_buf->buf)
729 		return QDF_STATUS_E_NOMEM;
730 
731 	cmd_tx_cmpl_log_buf->p_buf_tail_idx =
732 		&cmd_tx_cmpl_log_buf->buf_tail_idx;
733 
734 	/* WMI events when processed */
735 	event_log_buf->length = 0;
736 	event_log_buf->buf_tail_idx = 0;
737 	event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc(
738 		wmi_log_max_entry * sizeof(struct wmi_event_debug));
739 	event_log_buf->size = wmi_log_max_entry;
740 
741 	if (!event_log_buf->buf)
742 		return QDF_STATUS_E_NOMEM;
743 
744 	event_log_buf->p_buf_tail_idx = &event_log_buf->buf_tail_idx;
745 
746 	/* WMI events when queued */
747 	rx_event_log_buf->length = 0;
748 	rx_event_log_buf->buf_tail_idx = 0;
749 	rx_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc(
750 		wmi_log_max_entry * sizeof(struct wmi_event_debug));
751 	rx_event_log_buf->size = wmi_log_max_entry;
752 
753 	if (!rx_event_log_buf->buf)
754 		return QDF_STATUS_E_NOMEM;
755 
756 	rx_event_log_buf->p_buf_tail_idx = &rx_event_log_buf->buf_tail_idx;
757 
758 	/* WMI Management commands */
759 	mgmt_cmd_log_buf->length = 0;
760 	mgmt_cmd_log_buf->buf_tail_idx = 0;
761 	mgmt_cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc(
762 		wmi_mgmt_log_max_entry * sizeof(struct wmi_command_debug));
763 	mgmt_cmd_log_buf->size = wmi_mgmt_log_max_entry;
764 
765 	if (!mgmt_cmd_log_buf->buf)
766 		return QDF_STATUS_E_NOMEM;
767 
768 	mgmt_cmd_log_buf->p_buf_tail_idx = &mgmt_cmd_log_buf->buf_tail_idx;
769 
770 	/* WMI Management commands Tx completed*/
771 	mgmt_cmd_tx_cmp_log_buf->length = 0;
772 	mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0;
773 	mgmt_cmd_tx_cmp_log_buf->buf = (struct wmi_command_debug *)
774 		qdf_mem_malloc(
775 		wmi_mgmt_log_max_entry *
776 		sizeof(struct wmi_command_debug));
777 	mgmt_cmd_tx_cmp_log_buf->size = wmi_mgmt_log_max_entry;
778 
779 	if (!mgmt_cmd_tx_cmp_log_buf->buf)
780 		return QDF_STATUS_E_NOMEM;
781 
782 	mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx =
783 		&mgmt_cmd_tx_cmp_log_buf->buf_tail_idx;
784 
785 	/* WMI Management events when received */
786 	mgmt_event_log_buf->length = 0;
787 	mgmt_event_log_buf->buf_tail_idx = 0;
788 
789 	mgmt_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc(
790 		wmi_mgmt_log_max_entry *
791 		sizeof(struct wmi_event_debug));
792 	mgmt_event_log_buf->size = wmi_mgmt_log_max_entry;
793 
794 	if (!mgmt_event_log_buf->buf)
795 		return QDF_STATUS_E_NOMEM;
796 
797 	mgmt_event_log_buf->p_buf_tail_idx = &mgmt_event_log_buf->buf_tail_idx;
798 
799 	/* WMI diag events when received */
800 	diag_event_log_buf->length = 0;
801 	diag_event_log_buf->buf_tail_idx = 0;
802 
803 	diag_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc(
804 		wmi_diag_log_max_entry *
805 		sizeof(struct wmi_event_debug));
806 	diag_event_log_buf->size = wmi_diag_log_max_entry;
807 
808 	if (!diag_event_log_buf->buf)
809 		return QDF_STATUS_E_NOMEM;
810 
811 	diag_event_log_buf->p_buf_tail_idx = &diag_event_log_buf->buf_tail_idx;
812 
813 	qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock);
814 	wmi_handle->log_info.wmi_logging_enable = 1;
815 
816 	return QDF_STATUS_SUCCESS;
817 }
818 #endif
819 
820 /**
821  * wmi_log_buffer_free() - Free all dynamic allocated buffer memory for
822  * event logging
823  * @wmi_handle: WMI handle.
824  *
825  * Return: None
826  */
827 #ifdef WMI_INTERFACE_EVENT_LOGGING_DYNAMIC_ALLOC
828 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle)
829 {
830 	if (wmi_handle->log_info.wmi_command_log_buf_info.buf)
831 		qdf_mem_free(wmi_handle->log_info.wmi_command_log_buf_info.buf);
832 	if (wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf)
833 		qdf_mem_free(
834 		wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf);
835 	if (wmi_handle->log_info.wmi_event_log_buf_info.buf)
836 		qdf_mem_free(wmi_handle->log_info.wmi_event_log_buf_info.buf);
837 	if (wmi_handle->log_info.wmi_rx_event_log_buf_info.buf)
838 		qdf_mem_free(
839 			wmi_handle->log_info.wmi_rx_event_log_buf_info.buf);
840 	if (wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf)
841 		qdf_mem_free(
842 			wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf);
843 	if (wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf)
844 		qdf_mem_free(
845 		wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf);
846 	if (wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf)
847 		qdf_mem_free(
848 			wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf);
849 	if (wmi_handle->log_info.wmi_diag_event_log_buf_info.buf)
850 		qdf_mem_free(
851 			wmi_handle->log_info.wmi_diag_event_log_buf_info.buf);
852 	wmi_handle->log_info.wmi_logging_enable = 0;
853 	qdf_spinlock_destroy(&wmi_handle->log_info.wmi_record_lock);
854 }
855 #else
856 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle)
857 {
858 	/* Do Nothing */
859 }
860 #endif
861 
862 /**
863  * wmi_print_cmd_log_buffer() - an output agnostic wmi command log printer
864  * @log_buffer: the command log buffer metadata of the buffer to print
865  * @count: the maximum number of entries to print
866  * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper
867  * @print_priv: any data required by the print method, e.g. a file handle
868  *
869  * Return: None
870  */
871 static void
872 wmi_print_cmd_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count,
873 			 qdf_abstract_print *print, void *print_priv)
874 {
875 	static const int data_len =
876 		WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t);
877 	char str[128];
878 	uint32_t idx;
879 
880 	if (count > log_buffer->size)
881 		count = log_buffer->size;
882 	if (count > log_buffer->length)
883 		count = log_buffer->length;
884 
885 	/* subtract count from index, and wrap if necessary */
886 	idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count;
887 	idx %= log_buffer->size;
888 
889 	print(print_priv, "Time (seconds)      Cmd Id              Payload");
890 	while (count) {
891 		struct wmi_command_debug *cmd_log = (struct wmi_command_debug *)
892 			&((struct wmi_command_debug *)log_buffer->buf)[idx];
893 		uint64_t secs, usecs;
894 		int len = 0;
895 		int i;
896 
897 		qdf_log_timestamp_to_secs(cmd_log->time, &secs, &usecs);
898 		len += scnprintf(str + len, sizeof(str) - len,
899 				 "% 8lld.%06lld    %6u (0x%06x)    ",
900 				 secs, usecs,
901 				 cmd_log->command, cmd_log->command);
902 		for (i = 0; i < data_len; ++i) {
903 			len += scnprintf(str + len, sizeof(str) - len,
904 					 "0x%08x ", cmd_log->data[i]);
905 		}
906 
907 		print(print_priv, str);
908 
909 		--count;
910 		++idx;
911 		if (idx >= log_buffer->size)
912 			idx = 0;
913 	}
914 }
915 
916 /**
917  * wmi_print_event_log_buffer() - an output agnostic wmi event log printer
918  * @log_buffer: the event log buffer metadata of the buffer to print
919  * @count: the maximum number of entries to print
920  * @print: an abstract print method, e.g. a qdf_print() or seq_printf() wrapper
921  * @print_priv: any data required by the print method, e.g. a file handle
922  *
923  * Return: None
924  */
925 static void
926 wmi_print_event_log_buffer(struct wmi_log_buf_t *log_buffer, uint32_t count,
927 			   qdf_abstract_print *print, void *print_priv)
928 {
929 	static const int data_len =
930 		WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH / sizeof(uint32_t);
931 	char str[128];
932 	uint32_t idx;
933 
934 	if (count > log_buffer->size)
935 		count = log_buffer->size;
936 	if (count > log_buffer->length)
937 		count = log_buffer->length;
938 
939 	/* subtract count from index, and wrap if necessary */
940 	idx = log_buffer->size + *log_buffer->p_buf_tail_idx - count;
941 	idx %= log_buffer->size;
942 
943 	print(print_priv, "Time (seconds)      Event Id             Payload");
944 	while (count) {
945 		struct wmi_event_debug *event_log = (struct wmi_event_debug *)
946 			&((struct wmi_event_debug *)log_buffer->buf)[idx];
947 		uint64_t secs, usecs;
948 		int len = 0;
949 		int i;
950 
951 		qdf_log_timestamp_to_secs(event_log->time, &secs, &usecs);
952 		len += scnprintf(str + len, sizeof(str) - len,
953 				 "% 8lld.%06lld    %6u (0x%06x)    ",
954 				 secs, usecs,
955 				 event_log->event, event_log->event);
956 		for (i = 0; i < data_len; ++i) {
957 			len += scnprintf(str + len, sizeof(str) - len,
958 					 "0x%08x ", event_log->data[i]);
959 		}
960 
961 		print(print_priv, str);
962 
963 		--count;
964 		++idx;
965 		if (idx >= log_buffer->size)
966 			idx = 0;
967 	}
968 }
969 
970 inline void
971 wmi_print_cmd_log(wmi_unified_t wmi, uint32_t count,
972 		  qdf_abstract_print *print, void *print_priv)
973 {
974 	wmi_print_cmd_log_buffer(
975 		&wmi->log_info.wmi_command_log_buf_info,
976 		count, print, print_priv);
977 }
978 
979 inline void
980 wmi_print_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count,
981 			 qdf_abstract_print *print, void *print_priv)
982 {
983 	wmi_print_cmd_log_buffer(
984 		&wmi->log_info.wmi_command_tx_cmp_log_buf_info,
985 		count, print, print_priv);
986 }
987 
988 inline void
989 wmi_print_mgmt_cmd_log(wmi_unified_t wmi, uint32_t count,
990 		       qdf_abstract_print *print, void *print_priv)
991 {
992 	wmi_print_cmd_log_buffer(
993 		&wmi->log_info.wmi_mgmt_command_log_buf_info,
994 		count, print, print_priv);
995 }
996 
997 inline void
998 wmi_print_mgmt_cmd_tx_cmp_log(wmi_unified_t wmi, uint32_t count,
999 			      qdf_abstract_print *print, void *print_priv)
1000 {
1001 	wmi_print_cmd_log_buffer(
1002 		&wmi->log_info.wmi_mgmt_command_tx_cmp_log_buf_info,
1003 		count, print, print_priv);
1004 }
1005 
1006 inline void
1007 wmi_print_event_log(wmi_unified_t wmi, uint32_t count,
1008 		    qdf_abstract_print *print, void *print_priv)
1009 {
1010 	wmi_print_event_log_buffer(
1011 		&wmi->log_info.wmi_event_log_buf_info,
1012 		count, print, print_priv);
1013 }
1014 
1015 inline void
1016 wmi_print_rx_event_log(wmi_unified_t wmi, uint32_t count,
1017 		       qdf_abstract_print *print, void *print_priv)
1018 {
1019 	wmi_print_event_log_buffer(
1020 		&wmi->log_info.wmi_rx_event_log_buf_info,
1021 		count, print, print_priv);
1022 }
1023 
1024 inline void
1025 wmi_print_mgmt_event_log(wmi_unified_t wmi, uint32_t count,
1026 			 qdf_abstract_print *print, void *print_priv)
1027 {
1028 	wmi_print_event_log_buffer(
1029 		&wmi->log_info.wmi_mgmt_event_log_buf_info,
1030 		count, print, print_priv);
1031 }
1032 
1033 
1034 /* debugfs routines*/
1035 
1036 /**
1037  * debug_wmi_##func_base##_show() - debugfs functions to display content of
1038  * command and event buffers. Macro uses max buffer length to display
1039  * buffer when it is wraparound.
1040  *
1041  * @m: debugfs handler to access wmi_handle
1042  * @v: Variable arguments (not used)
1043  *
1044  * Return: Length of characters printed
1045  */
1046 #define GENERATE_COMMAND_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size)	\
1047 	static int debug_wmi_##func_base##_show(struct seq_file *m,	\
1048 						void *v)		\
1049 	{								\
1050 		wmi_unified_t wmi_handle = (wmi_unified_t) m->private;	\
1051 		struct wmi_log_buf_t *wmi_log =				\
1052 			&wmi_handle->log_info.wmi_##func_base##_buf_info;\
1053 		int pos, nread, outlen;					\
1054 		int i;							\
1055 		uint64_t secs, usecs;					\
1056 									\
1057 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);\
1058 		if (!wmi_log->length) {					\
1059 			qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\
1060 			return wmi_bp_seq_printf(m,			\
1061 			"no elements to read from ring buffer!\n");	\
1062 		}							\
1063 									\
1064 		if (wmi_log->length <= wmi_ring_size)			\
1065 			nread = wmi_log->length;			\
1066 		else							\
1067 			nread = wmi_ring_size;				\
1068 									\
1069 		if (*(wmi_log->p_buf_tail_idx) == 0)			\
1070 			/* tail can be 0 after wrap-around */		\
1071 			pos = wmi_ring_size - 1;			\
1072 		else							\
1073 			pos = *(wmi_log->p_buf_tail_idx) - 1;		\
1074 									\
1075 		outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\
1076 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\
1077 		while (nread--) {					\
1078 			struct wmi_command_debug *wmi_record;		\
1079 									\
1080 			wmi_record = (struct wmi_command_debug *)	\
1081 			&(((struct wmi_command_debug *)wmi_log->buf)[pos]);\
1082 			outlen += wmi_bp_seq_printf(m, "CMD ID = %x\n",	\
1083 				(wmi_record->command));			\
1084 			qdf_log_timestamp_to_secs(wmi_record->time, &secs,\
1085 				&usecs);				\
1086 			outlen +=					\
1087 			wmi_bp_seq_printf(m, "CMD TIME = [%llu.%06llu]\n",\
1088 				secs, usecs);				\
1089 			outlen += wmi_bp_seq_printf(m, "CMD = ");	\
1090 			for (i = 0; i < (wmi_record_max_length/		\
1091 					sizeof(uint32_t)); i++)		\
1092 				outlen += wmi_bp_seq_printf(m, "%x ",	\
1093 					wmi_record->data[i]);		\
1094 			outlen += wmi_bp_seq_printf(m, "\n");		\
1095 									\
1096 			if (pos == 0)					\
1097 				pos = wmi_ring_size - 1;		\
1098 			else						\
1099 				pos--;					\
1100 		}							\
1101 		return outlen;						\
1102 	}								\
1103 
1104 #define GENERATE_EVENT_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size)	\
1105 	static int debug_wmi_##func_base##_show(struct seq_file *m,	\
1106 						void *v)		\
1107 	{								\
1108 		wmi_unified_t wmi_handle = (wmi_unified_t) m->private;	\
1109 		struct wmi_log_buf_t *wmi_log =				\
1110 			&wmi_handle->log_info.wmi_##func_base##_buf_info;\
1111 		int pos, nread, outlen;					\
1112 		int i;							\
1113 		uint64_t secs, usecs;					\
1114 									\
1115 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);\
1116 		if (!wmi_log->length) {					\
1117 			qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\
1118 			return wmi_bp_seq_printf(m,			\
1119 			"no elements to read from ring buffer!\n");	\
1120 		}							\
1121 									\
1122 		if (wmi_log->length <= wmi_ring_size)			\
1123 			nread = wmi_log->length;			\
1124 		else							\
1125 			nread = wmi_ring_size;				\
1126 									\
1127 		if (*(wmi_log->p_buf_tail_idx) == 0)			\
1128 			/* tail can be 0 after wrap-around */		\
1129 			pos = wmi_ring_size - 1;			\
1130 		else							\
1131 			pos = *(wmi_log->p_buf_tail_idx) - 1;		\
1132 									\
1133 		outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\
1134 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\
1135 		while (nread--) {					\
1136 			struct wmi_event_debug *wmi_record;		\
1137 									\
1138 			wmi_record = (struct wmi_event_debug *)		\
1139 			&(((struct wmi_event_debug *)wmi_log->buf)[pos]);\
1140 			qdf_log_timestamp_to_secs(wmi_record->time, &secs,\
1141 				&usecs);				\
1142 			outlen += wmi_bp_seq_printf(m, "Event ID = %x\n",\
1143 				(wmi_record->event));			\
1144 			outlen +=					\
1145 			wmi_bp_seq_printf(m, "Event TIME = [%llu.%06llu]\n",\
1146 				secs, usecs);				\
1147 			outlen += wmi_bp_seq_printf(m, "CMD = ");	\
1148 			for (i = 0; i < (wmi_record_max_length/		\
1149 					sizeof(uint32_t)); i++)		\
1150 				outlen += wmi_bp_seq_printf(m, "%x ",	\
1151 					wmi_record->data[i]);		\
1152 			outlen += wmi_bp_seq_printf(m, "\n");		\
1153 									\
1154 			if (pos == 0)					\
1155 				pos = wmi_ring_size - 1;		\
1156 			else						\
1157 				pos--;					\
1158 		}							\
1159 		return outlen;						\
1160 	}
1161 
1162 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_log, wmi_display_size);
1163 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_tx_cmp_log, wmi_display_size);
1164 GENERATE_EVENT_DEBUG_SHOW_FUNCS(event_log, wmi_display_size);
1165 GENERATE_EVENT_DEBUG_SHOW_FUNCS(rx_event_log, wmi_display_size);
1166 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_log, wmi_display_size);
1167 GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_tx_cmp_log,
1168 					wmi_display_size);
1169 GENERATE_EVENT_DEBUG_SHOW_FUNCS(mgmt_event_log, wmi_display_size);
1170 
1171 /**
1172  * debug_wmi_enable_show() - debugfs functions to display enable state of
1173  * wmi logging feature.
1174  *
1175  * @m: debugfs handler to access wmi_handle
1176  * @v: Variable arguments (not used)
1177  *
1178  * Return: always 1
1179  */
1180 static int debug_wmi_enable_show(struct seq_file *m, void *v)
1181 {
1182 	wmi_unified_t wmi_handle = (wmi_unified_t) m->private;
1183 
1184 	return wmi_bp_seq_printf(m, "%d\n",
1185 			wmi_handle->log_info.wmi_logging_enable);
1186 }
1187 
1188 /**
1189  * debug_wmi_log_size_show() - debugfs functions to display configured size of
1190  * wmi logging command/event buffer and management command/event buffer.
1191  *
1192  * @m: debugfs handler to access wmi_handle
1193  * @v: Variable arguments (not used)
1194  *
1195  * Return: Length of characters printed
1196  */
1197 static int debug_wmi_log_size_show(struct seq_file *m, void *v)
1198 {
1199 
1200 	wmi_bp_seq_printf(m, "WMI command/event log max size:%d\n",
1201 				wmi_log_max_entry);
1202 	return wmi_bp_seq_printf(m,
1203 			"WMI management command/events log max size:%d\n",
1204 			wmi_mgmt_log_max_entry);
1205 }
1206 
1207 /**
1208  * debug_wmi_##func_base##_write() - debugfs functions to clear
1209  * wmi logging command/event buffer and management command/event buffer.
1210  *
1211  * @file: file handler to access wmi_handle
1212  * @buf: received data buffer
1213  * @count: length of received buffer
1214  * @ppos: Not used
1215  *
1216  * Return: count
1217  */
1218 #define GENERATE_DEBUG_WRITE_FUNCS(func_base, wmi_ring_size, wmi_record_type)\
1219 	static ssize_t debug_wmi_##func_base##_write(struct file *file,	\
1220 				const char __user *buf,			\
1221 				size_t count, loff_t *ppos)		\
1222 	{								\
1223 		int k, ret;						\
1224 		wmi_unified_t wmi_handle =				\
1225 			((struct seq_file *)file->private_data)->private;\
1226 		struct wmi_log_buf_t *wmi_log = &wmi_handle->log_info.	\
1227 				wmi_##func_base##_buf_info;		\
1228 		char locbuf[50];					\
1229 									\
1230 		if ((!buf) || (count > 50))				\
1231 			return -EFAULT;					\
1232 									\
1233 		if (copy_from_user(locbuf, buf, count))			\
1234 			return -EFAULT;					\
1235 									\
1236 		ret = sscanf(locbuf, "%d", &k);				\
1237 		if ((ret != 1) || (k != 0)) {                           \
1238 			WMI_LOGE("Wrong input, echo 0 to clear the wmi buffer");\
1239 			return -EINVAL;					\
1240 		}							\
1241 									\
1242 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);\
1243 		qdf_mem_zero(wmi_log->buf, wmi_ring_size *		\
1244 				sizeof(struct wmi_record_type));	\
1245 		wmi_log->length = 0;					\
1246 		*(wmi_log->p_buf_tail_idx) = 0;				\
1247 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);\
1248 									\
1249 		return count;						\
1250 	}
1251 
1252 GENERATE_DEBUG_WRITE_FUNCS(command_log, wmi_log_max_entry,
1253 					wmi_command_debug);
1254 GENERATE_DEBUG_WRITE_FUNCS(command_tx_cmp_log, wmi_log_max_entry,
1255 					wmi_command_debug);
1256 GENERATE_DEBUG_WRITE_FUNCS(event_log, wmi_log_max_entry,
1257 					wmi_event_debug);
1258 GENERATE_DEBUG_WRITE_FUNCS(rx_event_log, wmi_log_max_entry,
1259 					wmi_event_debug);
1260 GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_log, wmi_mgmt_log_max_entry,
1261 					wmi_command_debug);
1262 GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_tx_cmp_log,
1263 		wmi_mgmt_log_max_entry, wmi_command_debug);
1264 GENERATE_DEBUG_WRITE_FUNCS(mgmt_event_log, wmi_mgmt_log_max_entry,
1265 					wmi_event_debug);
1266 
1267 /**
1268  * debug_wmi_enable_write() - debugfs functions to enable/disable
1269  * wmi logging feature.
1270  *
1271  * @file: file handler to access wmi_handle
1272  * @buf: received data buffer
1273  * @count: length of received buffer
1274  * @ppos: Not used
1275  *
1276  * Return: count
1277  */
1278 static ssize_t debug_wmi_enable_write(struct file *file, const char __user *buf,
1279 					size_t count, loff_t *ppos)
1280 {
1281 	wmi_unified_t wmi_handle =
1282 		((struct seq_file *)file->private_data)->private;
1283 	int k, ret;
1284 	char locbuf[50];
1285 
1286 	if ((!buf) || (count > 50))
1287 		return -EFAULT;
1288 
1289 	if (copy_from_user(locbuf, buf, count))
1290 		return -EFAULT;
1291 
1292 	ret = sscanf(locbuf, "%d", &k);
1293 	if ((ret != 1) || ((k != 0) && (k != 1)))
1294 		return -EINVAL;
1295 
1296 	wmi_handle->log_info.wmi_logging_enable = k;
1297 	return count;
1298 }
1299 
1300 /**
1301  * debug_wmi_log_size_write() - reserved.
1302  *
1303  * @file: file handler to access wmi_handle
1304  * @buf: received data buffer
1305  * @count: length of received buffer
1306  * @ppos: Not used
1307  *
1308  * Return: count
1309  */
1310 static ssize_t debug_wmi_log_size_write(struct file *file,
1311 		const char __user *buf, size_t count, loff_t *ppos)
1312 {
1313 	return -EINVAL;
1314 }
1315 
1316 /* Structure to maintain debug information */
1317 struct wmi_debugfs_info {
1318 	const char *name;
1319 	const struct file_operations *ops;
1320 };
1321 
1322 #define DEBUG_FOO(func_base) { .name = #func_base,			\
1323 	.ops = &debug_##func_base##_ops }
1324 
1325 /**
1326  * debug_##func_base##_open() - Open debugfs entry for respective command
1327  * and event buffer.
1328  *
1329  * @inode: node for debug dir entry
1330  * @file: file handler
1331  *
1332  * Return: open status
1333  */
1334 #define GENERATE_DEBUG_STRUCTS(func_base)				\
1335 	static int debug_##func_base##_open(struct inode *inode,	\
1336 						struct file *file)	\
1337 	{								\
1338 		return single_open(file, debug_##func_base##_show,	\
1339 				inode->i_private);			\
1340 	}								\
1341 									\
1342 									\
1343 	static struct file_operations debug_##func_base##_ops = {	\
1344 		.open		= debug_##func_base##_open,		\
1345 		.read		= seq_read,				\
1346 		.llseek		= seq_lseek,				\
1347 		.write		= debug_##func_base##_write,		\
1348 		.release	= single_release,			\
1349 	};
1350 
1351 GENERATE_DEBUG_STRUCTS(wmi_command_log);
1352 GENERATE_DEBUG_STRUCTS(wmi_command_tx_cmp_log);
1353 GENERATE_DEBUG_STRUCTS(wmi_event_log);
1354 GENERATE_DEBUG_STRUCTS(wmi_rx_event_log);
1355 GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_log);
1356 GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_tx_cmp_log);
1357 GENERATE_DEBUG_STRUCTS(wmi_mgmt_event_log);
1358 GENERATE_DEBUG_STRUCTS(wmi_enable);
1359 GENERATE_DEBUG_STRUCTS(wmi_log_size);
1360 
1361 struct wmi_debugfs_info wmi_debugfs_infos[NUM_DEBUG_INFOS] = {
1362 	DEBUG_FOO(wmi_command_log),
1363 	DEBUG_FOO(wmi_command_tx_cmp_log),
1364 	DEBUG_FOO(wmi_event_log),
1365 	DEBUG_FOO(wmi_rx_event_log),
1366 	DEBUG_FOO(wmi_mgmt_command_log),
1367 	DEBUG_FOO(wmi_mgmt_command_tx_cmp_log),
1368 	DEBUG_FOO(wmi_mgmt_event_log),
1369 	DEBUG_FOO(wmi_enable),
1370 	DEBUG_FOO(wmi_log_size),
1371 };
1372 
1373 
1374 /**
1375  * wmi_debugfs_create() - Create debug_fs entry for wmi logging.
1376  *
1377  * @wmi_handle: wmi handle
1378  * @par_entry: debug directory entry
1379  * @id: Index to debug info data array
1380  *
1381  * Return: none
1382  */
1383 static void wmi_debugfs_create(wmi_unified_t wmi_handle,
1384 			       struct dentry *par_entry)
1385 {
1386 	int i;
1387 
1388 	if (!par_entry)
1389 		goto out;
1390 
1391 	for (i = 0; i < NUM_DEBUG_INFOS; ++i) {
1392 		wmi_handle->debugfs_de[i] = debugfs_create_file(
1393 				wmi_debugfs_infos[i].name, 0644, par_entry,
1394 				wmi_handle, wmi_debugfs_infos[i].ops);
1395 
1396 		if (!wmi_handle->debugfs_de[i]) {
1397 			WMI_LOGE("debug Entry creation failed!");
1398 			goto out;
1399 		}
1400 	}
1401 
1402 	return;
1403 
1404 out:
1405 	WMI_LOGE("debug Entry creation failed!");
1406 	wmi_log_buffer_free(wmi_handle);
1407 	return;
1408 }
1409 
1410 /**
1411  * wmi_debugfs_remove() - Remove debugfs entry for wmi logging.
1412  * @wmi_handle: wmi handle
1413  * @dentry: debugfs directory entry
1414  * @id: Index to debug info data array
1415  *
1416  * Return: none
1417  */
1418 static void wmi_debugfs_remove(wmi_unified_t wmi_handle)
1419 {
1420 	int i;
1421 	struct dentry *dentry = wmi_handle->log_info.wmi_log_debugfs_dir;
1422 
1423 	if (dentry) {
1424 		for (i = 0; i < NUM_DEBUG_INFOS; ++i) {
1425 			if (wmi_handle->debugfs_de[i])
1426 				wmi_handle->debugfs_de[i] = NULL;
1427 		}
1428 	}
1429 
1430 	if (dentry)
1431 		debugfs_remove_recursive(dentry);
1432 }
1433 
1434 /**
1435  * wmi_debugfs_init() - debugfs functions to create debugfs directory and to
1436  * create debugfs enteries.
1437  *
1438  * @h: wmi handler
1439  *
1440  * Return: init status
1441  */
1442 static QDF_STATUS wmi_debugfs_init(wmi_unified_t wmi_handle, uint32_t pdev_idx)
1443 {
1444 	char buf[32];
1445 
1446 	snprintf(buf, sizeof(buf), "WMI_SOC%u_PDEV%u",
1447 		 wmi_handle->soc->soc_idx, pdev_idx);
1448 
1449 	wmi_handle->log_info.wmi_log_debugfs_dir =
1450 		debugfs_create_dir(buf, NULL);
1451 
1452 	if (!wmi_handle->log_info.wmi_log_debugfs_dir) {
1453 		WMI_LOGE("error while creating debugfs dir for %s", buf);
1454 		return QDF_STATUS_E_FAILURE;
1455 	}
1456 	wmi_debugfs_create(wmi_handle,
1457 			   wmi_handle->log_info.wmi_log_debugfs_dir);
1458 
1459 	return QDF_STATUS_SUCCESS;
1460 }
1461 
1462 /**
1463  * wmi_mgmt_cmd_record() - Wrapper function for mgmt command logging macro
1464  *
1465  * @wmi_handle: wmi handle
1466  * @cmd: mgmt command
1467  * @header: pointer to 802.11 header
1468  * @vdev_id: vdev id
1469  * @chanfreq: channel frequency
1470  *
1471  * Return: none
1472  */
1473 void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd,
1474 			void *header, uint32_t vdev_id, uint32_t chanfreq)
1475 {
1476 
1477 	uint32_t data[CUSTOM_MGMT_CMD_DATA_SIZE];
1478 
1479 	data[0] = ((struct wmi_command_header *)header)->type;
1480 	data[1] = ((struct wmi_command_header *)header)->sub_type;
1481 	data[2] = vdev_id;
1482 	data[3] = chanfreq;
1483 
1484 	qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
1485 
1486 	WMI_MGMT_COMMAND_RECORD(wmi_handle, cmd, (uint8_t *)data);
1487 
1488 	qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
1489 }
1490 #else
1491 /**
1492  * wmi_debugfs_remove() - Remove debugfs entry for wmi logging.
1493  * @wmi_handle: wmi handle
1494  * @dentry: debugfs directory entry
1495  * @id: Index to debug info data array
1496  *
1497  * Return: none
1498  */
1499 static void wmi_debugfs_remove(wmi_unified_t wmi_handle) { }
1500 void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd,
1501 			void *header, uint32_t vdev_id, uint32_t chanfreq) { }
1502 static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) { }
1503 #endif /*WMI_INTERFACE_EVENT_LOGGING */
1504 qdf_export_symbol(wmi_mgmt_cmd_record);
1505 
1506 int wmi_get_host_credits(wmi_unified_t wmi_handle);
1507 /* WMI buffer APIs */
1508 
1509 #ifdef NBUF_MEMORY_DEBUG
1510 wmi_buf_t
1511 wmi_buf_alloc_debug(wmi_unified_t wmi_handle, uint32_t len,
1512 		    const char *func_name,
1513 		    uint32_t line_num)
1514 {
1515 	wmi_buf_t wmi_buf;
1516 
1517 	if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) {
1518 		QDF_ASSERT(0);
1519 		return NULL;
1520 	}
1521 
1522 	wmi_buf = wbuff_buff_get(wmi_handle->wbuff_handle, len, func_name,
1523 				 line_num);
1524 	if (!wmi_buf)
1525 		wmi_buf = qdf_nbuf_alloc_debug(NULL,
1526 					       roundup(len + WMI_MIN_HEAD_ROOM,
1527 						       4),
1528 					       WMI_MIN_HEAD_ROOM, 4, false,
1529 					       func_name, line_num);
1530 	if (!wmi_buf)
1531 		return NULL;
1532 
1533 	/* Clear the wmi buffer */
1534 	OS_MEMZERO(qdf_nbuf_data(wmi_buf), len);
1535 
1536 	/*
1537 	 * Set the length of the buffer to match the allocation size.
1538 	 */
1539 	qdf_nbuf_set_pktlen(wmi_buf, len);
1540 
1541 	return wmi_buf;
1542 }
1543 qdf_export_symbol(wmi_buf_alloc_debug);
1544 
1545 void wmi_buf_free(wmi_buf_t net_buf)
1546 {
1547 	net_buf = wbuff_buff_put(net_buf);
1548 	if (net_buf)
1549 		qdf_nbuf_free(net_buf);
1550 }
1551 qdf_export_symbol(wmi_buf_free);
1552 #else
1553 wmi_buf_t wmi_buf_alloc_fl(wmi_unified_t wmi_handle, uint32_t len,
1554 			   const char *func, uint32_t line)
1555 {
1556 	wmi_buf_t wmi_buf;
1557 
1558 	if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) {
1559 		QDF_DEBUG_PANIC("Invalid length %u (via %s:%u)",
1560 				len, func, line);
1561 		return NULL;
1562 	}
1563 
1564 	wmi_buf = wbuff_buff_get(wmi_handle->wbuff_handle, len, __func__,
1565 				 __LINE__);
1566 	if (!wmi_buf)
1567 		wmi_buf = qdf_nbuf_alloc_fl(NULL, roundup(len +
1568 				WMI_MIN_HEAD_ROOM, 4), WMI_MIN_HEAD_ROOM, 4,
1569 				false, func, line);
1570 
1571 	if (!wmi_buf) {
1572 		wmi_nofl_err("%s:%d, failed to alloc len:%d", func, line, len);
1573 		return NULL;
1574 	}
1575 
1576 	/* Clear the wmi buffer */
1577 	OS_MEMZERO(qdf_nbuf_data(wmi_buf), len);
1578 
1579 	/*
1580 	 * Set the length of the buffer to match the allocation size.
1581 	 */
1582 	qdf_nbuf_set_pktlen(wmi_buf, len);
1583 
1584 	return wmi_buf;
1585 }
1586 qdf_export_symbol(wmi_buf_alloc_fl);
1587 
1588 void wmi_buf_free(wmi_buf_t net_buf)
1589 {
1590 	net_buf = wbuff_buff_put(net_buf);
1591 	if (net_buf)
1592 		qdf_nbuf_free(net_buf);
1593 }
1594 qdf_export_symbol(wmi_buf_free);
1595 #endif
1596 
1597 /**
1598  * wmi_get_max_msg_len() - get maximum WMI message length
1599  * @wmi_handle: WMI handle.
1600  *
1601  * This function returns the maximum WMI message length
1602  *
1603  * Return: maximum WMI message length
1604  */
1605 uint16_t wmi_get_max_msg_len(wmi_unified_t wmi_handle)
1606 {
1607 	return wmi_handle->max_msg_len - WMI_MIN_HEAD_ROOM;
1608 }
1609 qdf_export_symbol(wmi_get_max_msg_len);
1610 
1611 #ifndef WMI_CMD_STRINGS
1612 static uint8_t *wmi_id_to_name(uint32_t wmi_command)
1613 {
1614 	return "Invalid WMI cmd";
1615 }
1616 #endif
1617 
1618 static inline void wmi_log_cmd_id(uint32_t cmd_id, uint32_t tag)
1619 {
1620 	WMI_LOGD("Send WMI command:%s command_id:%d htc_tag:%d\n",
1621 		 wmi_id_to_name(cmd_id), cmd_id, tag);
1622 }
1623 
1624 /**
1625  * wmi_is_pm_resume_cmd() - check if a cmd is part of the resume sequence
1626  * @cmd_id: command to check
1627  *
1628  * Return: true if the command is part of the resume sequence.
1629  */
1630 #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
1631 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id)
1632 {
1633 	switch (cmd_id) {
1634 	case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID:
1635 	case WMI_PDEV_RESUME_CMDID:
1636 		return true;
1637 
1638 	default:
1639 		return false;
1640 	}
1641 }
1642 
1643 #else
1644 static bool wmi_is_pm_resume_cmd(uint32_t cmd_id)
1645 {
1646 	return false;
1647 }
1648 
1649 #endif
1650 
1651 #ifdef FEATURE_WLAN_D0WOW
1652 static bool wmi_is_legacy_d0wow_disable_cmd(wmi_buf_t buf, uint32_t cmd_id)
1653 {
1654 	wmi_d0_wow_enable_disable_cmd_fixed_param *cmd;
1655 
1656 	if (cmd_id == WMI_D0_WOW_ENABLE_DISABLE_CMDID) {
1657 		cmd = (wmi_d0_wow_enable_disable_cmd_fixed_param *)
1658 			wmi_buf_data(buf);
1659 		if (!cmd->enable)
1660 			return true;
1661 		else
1662 			return false;
1663 	}
1664 
1665 	return false;
1666 }
1667 #else
1668 static bool wmi_is_legacy_d0wow_disable_cmd(wmi_buf_t buf, uint32_t cmd_id)
1669 {
1670 	return false;
1671 }
1672 
1673 #endif
1674 
1675 static inline void wmi_unified_debug_dump(wmi_unified_t wmi_handle)
1676 {
1677 	wmi_nofl_err("Endpoint ID = %d, Tx Queue Depth = %d, soc_id = %u, target type = %s",
1678 		     wmi_handle->wmi_endpoint_id,
1679 		     htc_get_tx_queue_depth(wmi_handle->htc_handle,
1680 					    wmi_handle->wmi_endpoint_id),
1681 		     wmi_handle->soc->soc_idx,
1682 		     (wmi_handle->target_type ==
1683 		      WMI_TLV_TARGET ? "WMI_TLV_TARGET" :
1684 						"WMI_NON_TLV_TARGET"));
1685 }
1686 
1687 #ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI
1688 QDF_STATUS wmi_unified_cmd_send_over_qmi(struct wmi_unified *wmi_handle,
1689 				    wmi_buf_t buf, uint32_t buflen,
1690 				    uint32_t cmd_id)
1691 {
1692 	QDF_STATUS status;
1693 	int32_t ret;
1694 
1695 	if (!qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR))) {
1696 		wmi_err("Failed to send cmd %x, no memory", cmd_id);
1697 		return QDF_STATUS_E_NOMEM;
1698 	}
1699 
1700 	qdf_mem_zero(qdf_nbuf_data(buf), sizeof(WMI_CMD_HDR));
1701 	WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id);
1702 	wmi_debug("Sending WMI_CMD_ID: %d over qmi", cmd_id);
1703 	status = qdf_wmi_send_recv_qmi(qdf_nbuf_data(buf),
1704 				       buflen + sizeof(WMI_CMD_HDR),
1705 				       wmi_handle,
1706 				       wmi_process_qmi_fw_event);
1707 	if (QDF_IS_STATUS_ERROR(status)) {
1708 		qdf_nbuf_pull_head(buf, sizeof(WMI_CMD_HDR));
1709 		wmi_warn("WMI send on QMI failed. Retrying WMI on HTC");
1710 	} else {
1711 		ret = qdf_atomic_inc_return(&wmi_handle->num_stats_over_qmi);
1712 		wmi_debug("num stats over qmi: %d", ret);
1713 		wmi_buf_free(buf);
1714 	}
1715 
1716 	return status;
1717 }
1718 
1719 static int __wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len)
1720 {
1721 	struct wmi_unified *wmi_handle = wmi_cb_ctx;
1722 	wmi_buf_t evt_buf;
1723 	uint32_t evt_id;
1724 
1725 	if (!wmi_handle || !buf)
1726 		return -EINVAL;
1727 
1728 	evt_buf = wmi_buf_alloc(wmi_handle, len);
1729 	if (!evt_buf)
1730 		return -ENOMEM;
1731 
1732 	qdf_mem_copy(qdf_nbuf_data(evt_buf), buf, len);
1733 	evt_id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
1734 	wmi_debug("Received WMI_EVT_ID: %d over qmi", evt_id);
1735 	wmi_process_fw_event(wmi_handle, evt_buf);
1736 
1737 	return 0;
1738 }
1739 
1740 int wmi_process_qmi_fw_event(void *wmi_cb_ctx, void *buf, int len)
1741 {
1742 	struct qdf_op_sync *op_sync;
1743 	int ret;
1744 
1745 	if (qdf_op_protect(&op_sync))
1746 		return -EINVAL;
1747 	ret = __wmi_process_qmi_fw_event(wmi_cb_ctx, buf, len);
1748 	qdf_op_unprotect(op_sync);
1749 
1750 	return ret;
1751 }
1752 #endif
1753 
1754 QDF_STATUS wmi_unified_cmd_send_fl(wmi_unified_t wmi_handle, wmi_buf_t buf,
1755 				   uint32_t len, uint32_t cmd_id,
1756 				   const char *func, uint32_t line)
1757 {
1758 	HTC_PACKET *pkt;
1759 	QDF_STATUS status;
1760 	uint16_t htc_tag = 0;
1761 
1762 	if (wmi_get_runtime_pm_inprogress(wmi_handle)) {
1763 		htc_tag = wmi_handle->ops->wmi_set_htc_tx_tag(wmi_handle, buf,
1764 							      cmd_id);
1765 	} else if (qdf_atomic_read(&wmi_handle->is_target_suspended) &&
1766 		   !wmi_is_pm_resume_cmd(cmd_id) &&
1767 		   !wmi_is_legacy_d0wow_disable_cmd(buf, cmd_id)) {
1768 			wmi_nofl_err("Target is suspended (via %s:%u)",
1769 					func, line);
1770 		return QDF_STATUS_E_BUSY;
1771 	}
1772 
1773 	if (wmi_handle->wmi_stopinprogress) {
1774 		wmi_nofl_err("%s:%d, WMI stop in progress, wmi_handle:%pK",
1775 			     func, line, wmi_handle);
1776 		return QDF_STATUS_E_INVAL;
1777 	}
1778 
1779 #ifndef WMI_NON_TLV_SUPPORT
1780 	/* Do sanity check on the TLV parameter structure */
1781 	if (wmi_handle->target_type == WMI_TLV_TARGET) {
1782 		void *buf_ptr = (void *)qdf_nbuf_data(buf);
1783 
1784 		if (wmi_handle->ops->wmi_check_command_params(NULL, buf_ptr, len, cmd_id)
1785 			!= 0) {
1786 			wmi_nofl_err("%s:%d, Invalid WMI Param Buffer for Cmd:%d",
1787 				     func, line, cmd_id);
1788 			return QDF_STATUS_E_INVAL;
1789 		}
1790 	}
1791 #endif
1792 
1793 	if (qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR)) == NULL) {
1794 		wmi_nofl_err("%s:%d, Failed to send cmd %x, no memory",
1795 			     func, line, cmd_id);
1796 		return QDF_STATUS_E_NOMEM;
1797 	}
1798 
1799 	qdf_mem_zero(qdf_nbuf_data(buf), sizeof(WMI_CMD_HDR));
1800 	WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id);
1801 
1802 	qdf_atomic_inc(&wmi_handle->pending_cmds);
1803 	if (qdf_atomic_read(&wmi_handle->pending_cmds) >=
1804 			wmi_handle->wmi_max_cmds) {
1805 		wmi_nofl_err("hostcredits = %d",
1806 			     wmi_get_host_credits(wmi_handle));
1807 		htc_dump_counter_info(wmi_handle->htc_handle);
1808 		qdf_atomic_dec(&wmi_handle->pending_cmds);
1809 		wmi_nofl_err("%s:%d, MAX %d WMI Pending cmds reached",
1810 			     func, line, wmi_handle->wmi_max_cmds);
1811 		wmi_unified_debug_dump(wmi_handle);
1812 		htc_ce_tasklet_debug_dump(wmi_handle->htc_handle);
1813 		qdf_trigger_self_recovery(QDF_WMI_EXCEED_MAX_PENDING_CMDS);
1814 		return QDF_STATUS_E_BUSY;
1815 	}
1816 
1817 	pkt = qdf_mem_malloc_fl(sizeof(*pkt), func, line);
1818 	if (!pkt) {
1819 		qdf_atomic_dec(&wmi_handle->pending_cmds);
1820 		return QDF_STATUS_E_NOMEM;
1821 	}
1822 
1823 	SET_HTC_PACKET_INFO_TX(pkt,
1824 			       NULL,
1825 			       qdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR),
1826 			       wmi_handle->wmi_endpoint_id, htc_tag);
1827 
1828 	SET_HTC_PACKET_NET_BUF_CONTEXT(pkt, buf);
1829 	wmi_log_cmd_id(cmd_id, htc_tag);
1830 	wmi_ext_dbg_msg_cmd_record(wmi_handle,
1831 				   qdf_nbuf_data(buf), qdf_nbuf_len(buf));
1832 #ifdef WMI_INTERFACE_EVENT_LOGGING
1833 	if (wmi_handle->log_info.wmi_logging_enable) {
1834 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
1835 		/*
1836 		 * Record 16 bytes of WMI cmd data -
1837 		 * exclude TLV and WMI headers
1838 		 *
1839 		 * WMI mgmt command already recorded in wmi_mgmt_cmd_record
1840 		 */
1841 		if (wmi_handle->ops->is_management_record(cmd_id) == false) {
1842 			WMI_COMMAND_RECORD(wmi_handle, cmd_id,
1843 					qdf_nbuf_data(buf) +
1844 			 wmi_handle->soc->buf_offset_command);
1845 		}
1846 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
1847 	}
1848 #endif
1849 
1850 	status = htc_send_pkt(wmi_handle->htc_handle, pkt);
1851 
1852 	if (QDF_STATUS_SUCCESS != status) {
1853 		qdf_atomic_dec(&wmi_handle->pending_cmds);
1854 		wmi_nofl_err("%s:%d, htc_send_pkt failed, status:%d",
1855 			     func, line, status);
1856 		qdf_mem_free(pkt);
1857 		return status;
1858 	}
1859 
1860 	return QDF_STATUS_SUCCESS;
1861 }
1862 qdf_export_symbol(wmi_unified_cmd_send_fl);
1863 
1864 /**
1865  * wmi_unified_get_event_handler_ix() - gives event handler's index
1866  * @wmi_handle: handle to wmi
1867  * @event_id: wmi  event id
1868  *
1869  * Return: event handler's index
1870  */
1871 static int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle,
1872 					    uint32_t event_id)
1873 {
1874 	uint32_t idx = 0;
1875 	int32_t invalid_idx = -1;
1876 	struct wmi_soc *soc = wmi_handle->soc;
1877 
1878 	for (idx = 0; (idx < soc->max_event_idx &&
1879 		       idx < WMI_UNIFIED_MAX_EVENT); ++idx) {
1880 		if (wmi_handle->event_id[idx] == event_id &&
1881 		    wmi_handle->event_handler[idx]) {
1882 			return idx;
1883 		}
1884 	}
1885 
1886 	return invalid_idx;
1887 }
1888 
1889 /**
1890  * wmi_unified_register_event() - register wmi event handler
1891  * @wmi_handle: handle to wmi
1892  * @event_id: wmi event id
1893  * @handler_func: wmi event handler function
1894  *
1895  * Return: 0 on success
1896  */
1897 int wmi_unified_register_event(wmi_unified_t wmi_handle,
1898 				       uint32_t event_id,
1899 				       wmi_unified_event_handler handler_func)
1900 {
1901 	uint32_t idx = 0;
1902 	uint32_t evt_id;
1903 	struct wmi_soc *soc;
1904 
1905 	if (!wmi_handle) {
1906 		WMI_LOGE("WMI handle is NULL");
1907 		return QDF_STATUS_E_FAILURE;
1908 	}
1909 
1910 	soc = wmi_handle->soc;
1911 
1912 	if (event_id >= wmi_events_max ||
1913 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
1914 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1915 			  "%s: Event id %d is unavailable",
1916 					__func__, event_id);
1917 		return QDF_STATUS_E_FAILURE;
1918 	}
1919 	evt_id = wmi_handle->wmi_events[event_id];
1920 	if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) {
1921 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1922 			  "%s : event handler already registered 0x%x",
1923 				__func__, evt_id);
1924 		return QDF_STATUS_E_FAILURE;
1925 	}
1926 	if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) {
1927 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1928 			  "%s : no more event handlers 0x%x",
1929 					__func__, evt_id);
1930 		return QDF_STATUS_E_FAILURE;
1931 	}
1932 	idx = soc->max_event_idx;
1933 	wmi_handle->event_handler[idx] = handler_func;
1934 	wmi_handle->event_id[idx] = evt_id;
1935 	qdf_spin_lock_bh(&soc->ctx_lock);
1936 	wmi_handle->ctx[idx] = WMI_RX_UMAC_CTX;
1937 	qdf_spin_unlock_bh(&soc->ctx_lock);
1938 	soc->max_event_idx++;
1939 
1940 	return 0;
1941 }
1942 
1943 /**
1944  * wmi_unified_register_event_handler() - register wmi event handler
1945  * @wmi_handle: handle to wmi
1946  * @event_id: wmi event id
1947  * @handler_func: wmi event handler function
1948  * @rx_ctx: rx execution context for wmi rx events
1949  *
1950  * This API is to support legacy requirements. Will be deprecated in future.
1951  * Return: 0 on success
1952  */
1953 int wmi_unified_register_event_handler(wmi_unified_t wmi_handle,
1954 				       wmi_conv_event_id event_id,
1955 				       wmi_unified_event_handler handler_func,
1956 				       uint8_t rx_ctx)
1957 {
1958 	uint32_t idx = 0;
1959 	uint32_t evt_id;
1960 	struct wmi_soc *soc;
1961 
1962 	if (!wmi_handle) {
1963 		WMI_LOGE("WMI handle is NULL");
1964 		return QDF_STATUS_E_FAILURE;
1965 	}
1966 
1967 	soc = wmi_handle->soc;
1968 
1969 	if (event_id >= wmi_events_max ||
1970 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
1971 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
1972 			  "%s: Event id %d is unavailable",
1973 					__func__, event_id);
1974 		return QDF_STATUS_E_FAILURE;
1975 	}
1976 	evt_id = wmi_handle->wmi_events[event_id];
1977 
1978 	if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) {
1979 		WMI_LOGE("event handler already registered 0x%x",
1980 			  evt_id);
1981 		return QDF_STATUS_E_FAILURE;
1982 	}
1983 	if (soc->max_event_idx == WMI_UNIFIED_MAX_EVENT) {
1984 		WMI_LOGE("no more event handlers 0x%x",
1985 			  evt_id);
1986 		return QDF_STATUS_E_FAILURE;
1987 	}
1988 	QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG,
1989 		  "Registered event handler for event 0x%8x", evt_id);
1990 	idx = soc->max_event_idx;
1991 	wmi_handle->event_handler[idx] = handler_func;
1992 	wmi_handle->event_id[idx] = evt_id;
1993 	qdf_spin_lock_bh(&soc->ctx_lock);
1994 	wmi_handle->ctx[idx] = rx_ctx;
1995 	qdf_spin_unlock_bh(&soc->ctx_lock);
1996 	soc->max_event_idx++;
1997 
1998 	return 0;
1999 }
2000 qdf_export_symbol(wmi_unified_register_event_handler);
2001 
2002 /**
2003  * wmi_unified_unregister_event() - unregister wmi event handler
2004  * @wmi_handle: handle to wmi
2005  * @event_id: wmi event id
2006  *
2007  * Return: 0 on success
2008  */
2009 int wmi_unified_unregister_event(wmi_unified_t wmi_handle,
2010 					 uint32_t event_id)
2011 {
2012 	uint32_t idx = 0;
2013 	uint32_t evt_id;
2014 	struct wmi_soc *soc = wmi_handle->soc;
2015 
2016 	if (event_id >= wmi_events_max ||
2017 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
2018 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
2019 			  "%s: Event id %d is unavailable",
2020 					__func__, event_id);
2021 		return QDF_STATUS_E_FAILURE;
2022 	}
2023 	evt_id = wmi_handle->wmi_events[event_id];
2024 
2025 	idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id);
2026 	if (idx == -1) {
2027 		WMI_LOGE("event handler is not registered: evt id 0x%x",
2028 			  evt_id);
2029 		return QDF_STATUS_E_FAILURE;
2030 	}
2031 	wmi_handle->event_handler[idx] = NULL;
2032 	wmi_handle->event_id[idx] = 0;
2033 	--soc->max_event_idx;
2034 	wmi_handle->event_handler[idx] =
2035 		wmi_handle->event_handler[soc->max_event_idx];
2036 	wmi_handle->event_id[idx] =
2037 		wmi_handle->event_id[soc->max_event_idx];
2038 
2039 	return 0;
2040 }
2041 
2042 /**
2043  * wmi_unified_unregister_event_handler() - unregister wmi event handler
2044  * @wmi_handle: handle to wmi
2045  * @event_id: wmi event id
2046  *
2047  * Return: 0 on success
2048  */
2049 int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle,
2050 					 wmi_conv_event_id event_id)
2051 {
2052 	uint32_t idx = 0;
2053 	uint32_t evt_id;
2054 	struct wmi_soc *soc;
2055 
2056 	if (!wmi_handle) {
2057 		WMI_LOGE("WMI handle is NULL");
2058 		return QDF_STATUS_E_FAILURE;
2059 	}
2060 
2061 	soc = wmi_handle->soc;
2062 
2063 	if (event_id >= wmi_events_max ||
2064 		wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) {
2065 		WMI_LOGE("Event id %d is unavailable",
2066 			  event_id);
2067 		return QDF_STATUS_E_FAILURE;
2068 	}
2069 	evt_id = wmi_handle->wmi_events[event_id];
2070 
2071 	idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id);
2072 	if (idx == -1) {
2073 		WMI_LOGE("event handler is not registered: evt id 0x%x",
2074 			  evt_id);
2075 		return QDF_STATUS_E_FAILURE;
2076 	}
2077 	wmi_handle->event_handler[idx] = NULL;
2078 	wmi_handle->event_id[idx] = 0;
2079 	--soc->max_event_idx;
2080 	wmi_handle->event_handler[idx] =
2081 		wmi_handle->event_handler[soc->max_event_idx];
2082 	wmi_handle->event_id[idx] =
2083 		wmi_handle->event_id[soc->max_event_idx];
2084 
2085 	return 0;
2086 }
2087 qdf_export_symbol(wmi_unified_unregister_event_handler);
2088 
2089 void wmi_process_fw_event_worker_thread_ctx(struct wmi_unified *wmi_handle,
2090 					    void *evt_buf)
2091 {
2092 
2093 	qdf_spin_lock_bh(&wmi_handle->eventq_lock);
2094 	qdf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf);
2095 	qdf_spin_unlock_bh(&wmi_handle->eventq_lock);
2096 	qdf_queue_work(0, wmi_handle->wmi_rx_work_queue,
2097 			&wmi_handle->rx_event_work);
2098 
2099 	return;
2100 }
2101 
2102 qdf_export_symbol(wmi_process_fw_event_worker_thread_ctx);
2103 
2104 uint32_t wmi_critical_events_in_flight(struct wmi_unified *wmi)
2105 {
2106 	return qdf_atomic_read(&wmi->critical_events_in_flight);
2107 }
2108 
2109 static bool
2110 wmi_is_event_critical(struct wmi_unified *wmi_handle, uint32_t event_id)
2111 {
2112 	if (wmi_handle->wmi_events[wmi_roam_synch_event_id] == event_id)
2113 		return true;
2114 
2115 	return false;
2116 }
2117 
2118 static void wmi_discard_fw_event(struct scheduler_msg *msg)
2119 {
2120 	struct wmi_process_fw_event_params *event_param;
2121 
2122 	if (!msg->bodyptr)
2123 		return;
2124 
2125 	event_param = (struct wmi_process_fw_event_params *)msg->bodyptr;
2126 	qdf_nbuf_free(event_param->evt_buf);
2127 	qdf_mem_free(msg->bodyptr);
2128 	msg->bodyptr = NULL;
2129 	msg->bodyval = 0;
2130 	msg->type = 0;
2131 }
2132 
2133 static int wmi_process_fw_event_handler(struct scheduler_msg *msg)
2134 {
2135 	struct wmi_process_fw_event_params *params =
2136 		(struct wmi_process_fw_event_params *)msg->bodyptr;
2137 	struct wmi_unified *wmi_handle;
2138 	uint32_t event_id;
2139 
2140 	wmi_handle = (struct wmi_unified *)params->wmi_handle;
2141 	event_id = WMI_GET_FIELD(qdf_nbuf_data(params->evt_buf),
2142 				 WMI_CMD_HDR, COMMANDID);
2143 	wmi_process_fw_event(wmi_handle, params->evt_buf);
2144 
2145 	if (wmi_is_event_critical(wmi_handle, event_id))
2146 		qdf_atomic_dec(&wmi_handle->critical_events_in_flight);
2147 
2148 	qdf_mem_free(msg->bodyptr);
2149 
2150 	return 0;
2151 }
2152 
2153 /**
2154  * wmi_process_fw_event_sched_thread_ctx() - common event handler to serialize
2155  *                                  event processing through scheduler thread
2156  * @ctx: wmi context
2157  * @ev: event buffer
2158  * @rx_ctx: rx execution context
2159  *
2160  * Return: 0 on success, errno on failure
2161  */
2162 static QDF_STATUS
2163 wmi_process_fw_event_sched_thread_ctx(struct wmi_unified *wmi,
2164 				      void *ev)
2165 {
2166 	struct wmi_process_fw_event_params *params_buf;
2167 	struct scheduler_msg msg = { 0 };
2168 	uint32_t event_id;
2169 	struct target_psoc_info *tgt_hdl;
2170 	bool is_wmi_ready = false;
2171 	struct wlan_objmgr_psoc *psoc;
2172 
2173 	psoc = target_if_get_psoc_from_scn_hdl(wmi->scn_handle);
2174 	if (!psoc) {
2175 		target_if_err("psoc is null");
2176 		qdf_nbuf_free(ev);
2177 		return QDF_STATUS_E_INVAL;
2178 	}
2179 
2180 	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
2181 	if (!tgt_hdl) {
2182 		wmi_err("target_psoc_info is null");
2183 		qdf_nbuf_free(ev);
2184 		return QDF_STATUS_E_INVAL;
2185 	}
2186 
2187 	is_wmi_ready = target_psoc_get_wmi_ready(tgt_hdl);
2188 	if (!is_wmi_ready) {
2189 		wmi_debug("fw event recvd before ready event processed");
2190 		wmi_debug("therefore use worker thread");
2191 		wmi_process_fw_event_worker_thread_ctx(wmi, ev);
2192 		return QDF_STATUS_E_INVAL;
2193 	}
2194 
2195 	params_buf = qdf_mem_malloc(sizeof(struct wmi_process_fw_event_params));
2196 	if (!params_buf) {
2197 		wmi_err("malloc failed");
2198 		qdf_nbuf_free(ev);
2199 		return QDF_STATUS_E_NOMEM;
2200 	}
2201 
2202 	params_buf->wmi_handle = wmi;
2203 	params_buf->evt_buf = ev;
2204 
2205 	event_id = WMI_GET_FIELD(qdf_nbuf_data(params_buf->evt_buf),
2206 				 WMI_CMD_HDR, COMMANDID);
2207 	if (wmi_is_event_critical(wmi, event_id))
2208 		qdf_atomic_inc(&wmi->critical_events_in_flight);
2209 
2210 	msg.bodyptr = params_buf;
2211 	msg.bodyval = 0;
2212 	msg.callback = wmi_process_fw_event_handler;
2213 	msg.flush_callback = wmi_discard_fw_event;
2214 
2215 	if (QDF_STATUS_SUCCESS !=
2216 		scheduler_post_message(QDF_MODULE_ID_TARGET_IF,
2217 				       QDF_MODULE_ID_TARGET_IF,
2218 				       QDF_MODULE_ID_TARGET_IF, &msg)) {
2219 		qdf_nbuf_free(ev);
2220 		qdf_mem_free(params_buf);
2221 		return QDF_STATUS_E_FAULT;
2222 	}
2223 
2224 	return QDF_STATUS_SUCCESS;
2225 }
2226 
2227 /**
2228  * wmi_get_pdev_ep: Get wmi handle based on endpoint
2229  * @soc: handle to wmi soc
2230  * @ep: endpoint id
2231  *
2232  * Return: none
2233  */
2234 static struct wmi_unified *wmi_get_pdev_ep(struct wmi_soc *soc,
2235 						HTC_ENDPOINT_ID ep)
2236 {
2237 	uint32_t i;
2238 
2239 	for (i = 0; i < WMI_MAX_RADIOS; i++)
2240 		if (soc->wmi_endpoint_id[i] == ep)
2241 			break;
2242 
2243 	if (i == WMI_MAX_RADIOS)
2244 		return NULL;
2245 
2246 	return soc->wmi_pdev[i];
2247 }
2248 
2249 /**
2250  * wmi_mtrace_rx() - Wrappper function for qdf_mtrace api
2251  * @message_id: 32-Bit Wmi message ID
2252  * @vdev_id: Vdev ID
2253  * @data: Actual message contents
2254  *
2255  * This function converts the 32-bit WMI message ID in 15-bit message ID
2256  * format for qdf_mtrace as in qdf_mtrace message there are only 15
2257  * bits reserved for message ID.
2258  * out of these 15-bits, 8-bits (From LSB) specifies the WMI_GRP_ID
2259  * and remaining 7-bits specifies the actual WMI command. With this
2260  * notation there can be maximum 256 groups and each group can have
2261  * max 128 commands can be supported.
2262  *
2263  * Return: None
2264  */
2265 static void wmi_mtrace_rx(uint32_t message_id, uint16_t vdev_id, uint32_t data)
2266 {
2267 	uint16_t mtrace_message_id;
2268 
2269 	mtrace_message_id = QDF_WMI_MTRACE_CMD_ID(message_id) |
2270 		(QDF_WMI_MTRACE_GRP_ID(message_id) <<
2271 						QDF_WMI_MTRACE_CMD_NUM_BITS);
2272 	qdf_mtrace(QDF_MODULE_ID_WMI, QDF_MODULE_ID_WMA,
2273 		   mtrace_message_id, vdev_id, data);
2274 }
2275 
2276 /**
2277  * wmi_control_rx() - process fw events callbacks
2278  * @ctx: handle to wmi
2279  * @htc_packet: pointer to htc packet
2280  *
2281  * Return: none
2282  */
2283 static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet)
2284 {
2285 	struct wmi_soc *soc = (struct wmi_soc *) ctx;
2286 	struct wmi_unified *wmi_handle;
2287 	wmi_buf_t evt_buf;
2288 	uint32_t id;
2289 	uint32_t idx = 0;
2290 	enum wmi_rx_exec_ctx exec_ctx;
2291 
2292 	evt_buf = (wmi_buf_t) htc_packet->pPktContext;
2293 
2294 	wmi_handle = wmi_get_pdev_ep(soc, htc_packet->Endpoint);
2295 	if (!wmi_handle) {
2296 		WMI_LOGE
2297 		("unable to get wmi_handle to Endpoint %d\n",
2298 		 htc_packet->Endpoint);
2299 		qdf_nbuf_free(evt_buf);
2300 		return;
2301 	}
2302 
2303 	id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
2304 	idx = wmi_unified_get_event_handler_ix(wmi_handle, id);
2305 	if (qdf_unlikely(idx == A_ERROR)) {
2306 		wmi_debug("no handler registered for event id 0x%x", id);
2307 		qdf_nbuf_free(evt_buf);
2308 		return;
2309 	}
2310 	wmi_mtrace_rx(id, 0xFF, idx);
2311 	qdf_spin_lock_bh(&soc->ctx_lock);
2312 	exec_ctx = wmi_handle->ctx[idx];
2313 	qdf_spin_unlock_bh(&soc->ctx_lock);
2314 
2315 #ifdef WMI_INTERFACE_EVENT_LOGGING
2316 	if (wmi_handle->log_info.wmi_logging_enable) {
2317 		uint8_t *data;
2318 		data = qdf_nbuf_data(evt_buf);
2319 
2320 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
2321 		/* Exclude 4 bytes of TLV header */
2322 		if (wmi_handle->ops->is_diag_event(id)) {
2323 			WMI_DIAG_RX_EVENT_RECORD(wmi_handle, id,
2324 				((uint8_t *) data +
2325 				wmi_handle->soc->buf_offset_event));
2326 		} else if (wmi_handle->ops->is_management_record(id)) {
2327 			WMI_MGMT_RX_EVENT_RECORD(wmi_handle, id,
2328 				((uint8_t *) data +
2329 				wmi_handle->soc->buf_offset_event));
2330 		} else {
2331 			WMI_RX_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data +
2332 				wmi_handle->soc->buf_offset_event));
2333 		}
2334 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
2335 	}
2336 #endif
2337 
2338 	if (exec_ctx == WMI_RX_WORK_CTX) {
2339 		wmi_process_fw_event_worker_thread_ctx
2340 					(wmi_handle, evt_buf);
2341 	} else if (exec_ctx == WMI_RX_TASKLET_CTX) {
2342 		wmi_process_fw_event(wmi_handle, evt_buf);
2343 	} else if (exec_ctx == WMI_RX_SERIALIZER_CTX) {
2344 		wmi_process_fw_event_sched_thread_ctx(wmi_handle, evt_buf);
2345 	} else {
2346 		WMI_LOGE("Invalid event context %d", exec_ctx);
2347 		qdf_nbuf_free(evt_buf);
2348 	}
2349 
2350 }
2351 
2352 /**
2353  * wmi_process_fw_event() - process any fw event
2354  * @wmi_handle: wmi handle
2355  * @evt_buf: fw event buffer
2356  *
2357  * This function process fw event in caller context
2358  *
2359  * Return: none
2360  */
2361 void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf)
2362 {
2363 	__wmi_control_rx(wmi_handle, evt_buf);
2364 }
2365 
2366 /**
2367  * __wmi_control_rx() - process serialize wmi event callback
2368  * @wmi_handle: wmi handle
2369  * @evt_buf: fw event buffer
2370  *
2371  * Return: none
2372  */
2373 void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf)
2374 {
2375 	uint32_t id;
2376 	uint8_t *data;
2377 	uint32_t len;
2378 	void *wmi_cmd_struct_ptr = NULL;
2379 #ifndef WMI_NON_TLV_SUPPORT
2380 	int tlv_ok_status = 0;
2381 #endif
2382 	uint32_t idx = 0;
2383 
2384 	id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID);
2385 
2386 	wmi_ext_dbg_msg_event_record(wmi_handle, qdf_nbuf_data(evt_buf),
2387 				     qdf_nbuf_len(evt_buf));
2388 
2389 	if (qdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL)
2390 		goto end;
2391 
2392 	data = qdf_nbuf_data(evt_buf);
2393 	len = qdf_nbuf_len(evt_buf);
2394 
2395 #ifndef WMI_NON_TLV_SUPPORT
2396 	if (wmi_handle->target_type == WMI_TLV_TARGET) {
2397 		/* Validate and pad(if necessary) the TLVs */
2398 		tlv_ok_status =
2399 			wmi_handle->ops->wmi_check_and_pad_event(wmi_handle->scn_handle,
2400 							data, len, id,
2401 							&wmi_cmd_struct_ptr);
2402 		if (tlv_ok_status != 0) {
2403 			QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
2404 				  "%s: Error: id=0x%x, wmitlv check status=%d",
2405 				  __func__, id, tlv_ok_status);
2406 			goto end;
2407 		}
2408 	}
2409 #endif
2410 
2411 	idx = wmi_unified_get_event_handler_ix(wmi_handle, id);
2412 	if (idx == A_ERROR) {
2413 		QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR,
2414 		   "%s : event handler is not registered: event id 0x%x",
2415 			__func__, id);
2416 		goto end;
2417 	}
2418 #ifdef WMI_INTERFACE_EVENT_LOGGING
2419 	if (wmi_handle->log_info.wmi_logging_enable) {
2420 		qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
2421 		/* Exclude 4 bytes of TLV header */
2422 		if (wmi_handle->ops->is_diag_event(id)) {
2423 			/*
2424 			 * skip diag event logging in WMI event buffer
2425 			 * as its already logged in WMI RX event buffer
2426 			 */
2427 		} else if (wmi_handle->ops->is_management_record(id)) {
2428 			/*
2429 			 * skip wmi mgmt event logging in WMI event buffer
2430 			 * as its already logged in WMI RX event buffer
2431 			 */
2432 		} else {
2433 			WMI_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data +
2434 					wmi_handle->soc->buf_offset_event));
2435 		}
2436 		qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
2437 	}
2438 #endif
2439 	/* Call the WMI registered event handler */
2440 	if (wmi_handle->target_type == WMI_TLV_TARGET)
2441 		wmi_handle->event_handler[idx] (wmi_handle->scn_handle,
2442 			wmi_cmd_struct_ptr, len);
2443 	else
2444 		wmi_handle->event_handler[idx] (wmi_handle->scn_handle,
2445 			data, len);
2446 
2447 end:
2448 	/* Free event buffer and allocated event tlv */
2449 #ifndef WMI_NON_TLV_SUPPORT
2450 	if (wmi_handle->target_type == WMI_TLV_TARGET)
2451 		wmi_handle->ops->wmi_free_allocated_event(id, &wmi_cmd_struct_ptr);
2452 #endif
2453 
2454 	qdf_nbuf_free(evt_buf);
2455 
2456 }
2457 
2458 #define WMI_WQ_WD_TIMEOUT (30 * 1000) /* 30s */
2459 
2460 static inline void wmi_workqueue_watchdog_warn(uint32_t msg_type_id)
2461 {
2462 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
2463 		  "%s: WLAN_BUG_RCA: Message type %x has exceeded its alloted time of %ds",
2464 		  __func__, msg_type_id, WMI_WQ_WD_TIMEOUT / 1000);
2465 }
2466 
2467 #ifdef CONFIG_SLUB_DEBUG_ON
2468 static void wmi_workqueue_watchdog_bite(void *arg)
2469 {
2470 	struct wmi_wq_dbg_info *info = arg;
2471 
2472 	wmi_workqueue_watchdog_warn(info->wd_msg_type_id);
2473 	qdf_print_thread_trace(info->task);
2474 
2475 	QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
2476 		  "%s: Going down for WMI WQ Watchdog Bite!", __func__);
2477 	QDF_BUG(0);
2478 }
2479 #else
2480 static inline void wmi_workqueue_watchdog_bite(void *arg)
2481 {
2482 	struct wmi_wq_dbg_info *info = arg;
2483 
2484 	wmi_workqueue_watchdog_warn(info->wd_msg_type_id);
2485 }
2486 #endif
2487 
2488 /**
2489  * wmi_rx_event_work() - process rx event in rx work queue context
2490  * @arg: opaque pointer to wmi handle
2491  *
2492  * This function process any fw event to serialize it through rx worker thread.
2493  *
2494  * Return: none
2495  */
2496 static void wmi_rx_event_work(void *arg)
2497 {
2498 	wmi_buf_t buf;
2499 	struct wmi_unified *wmi = arg;
2500 	qdf_timer_t wd_timer;
2501 	struct wmi_wq_dbg_info info;
2502 
2503 	/* initialize WMI workqueue watchdog timer */
2504 	qdf_timer_init(NULL, &wd_timer, &wmi_workqueue_watchdog_bite,
2505 			&info, QDF_TIMER_TYPE_SW);
2506 	qdf_spin_lock_bh(&wmi->eventq_lock);
2507 	buf = qdf_nbuf_queue_remove(&wmi->event_queue);
2508 	qdf_spin_unlock_bh(&wmi->eventq_lock);
2509 	while (buf) {
2510 		qdf_timer_start(&wd_timer, WMI_WQ_WD_TIMEOUT);
2511 		info.wd_msg_type_id =
2512 		   WMI_GET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID);
2513 		info.wmi_wq = wmi->wmi_rx_work_queue;
2514 		info.task = qdf_get_current_task();
2515 		__wmi_control_rx(wmi, buf);
2516 		qdf_timer_stop(&wd_timer);
2517 		qdf_spin_lock_bh(&wmi->eventq_lock);
2518 		buf = qdf_nbuf_queue_remove(&wmi->event_queue);
2519 		qdf_spin_unlock_bh(&wmi->eventq_lock);
2520 	}
2521 	qdf_timer_free(&wd_timer);
2522 }
2523 
2524 #ifdef FEATURE_RUNTIME_PM
2525 /**
2526  * wmi_runtime_pm_init() - initialize runtime pm wmi variables
2527  * @wmi_handle: wmi context
2528  */
2529 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle)
2530 {
2531 	qdf_atomic_init(&wmi_handle->runtime_pm_inprogress);
2532 }
2533 
2534 /**
2535  * wmi_set_runtime_pm_inprogress() - set runtime pm progress flag
2536  * @wmi_handle: wmi context
2537  * @val: runtime pm progress flag
2538  */
2539 void wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, A_BOOL val)
2540 {
2541 	qdf_atomic_set(&wmi_handle->runtime_pm_inprogress, val);
2542 }
2543 
2544 /**
2545  * wmi_get_runtime_pm_inprogress() - get runtime pm progress flag
2546  * @wmi_handle: wmi context
2547  */
2548 inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle)
2549 {
2550 	return qdf_atomic_read(&wmi_handle->runtime_pm_inprogress);
2551 }
2552 #else
2553 static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle)
2554 {
2555 }
2556 #endif
2557 
2558 /**
2559  * wmi_unified_get_soc_handle: Get WMI SoC handle
2560  * @param wmi_handle: WMI context got from wmi_attach
2561  *
2562  * return: Pointer to Soc handle
2563  */
2564 void *wmi_unified_get_soc_handle(struct wmi_unified *wmi_handle)
2565 {
2566 	return wmi_handle->soc;
2567 }
2568 
2569 /**
2570  * wmi_interface_logging_init: Interface looging init
2571  * @param wmi_handle: Pointer to wmi handle object
2572  *
2573  * return: None
2574  */
2575 #ifdef WMI_INTERFACE_EVENT_LOGGING
2576 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle,
2577 					      uint32_t pdev_idx)
2578 {
2579 	if (QDF_STATUS_SUCCESS == wmi_log_init(wmi_handle)) {
2580 		qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock);
2581 		wmi_debugfs_init(wmi_handle, pdev_idx);
2582 	}
2583 }
2584 #else
2585 static inline void wmi_interface_logging_init(struct wmi_unified *wmi_handle,
2586 					      uint32_t pdev_idx)
2587 {
2588 }
2589 #endif
2590 
2591 /**
2592  * wmi_unified_get_pdev_handle: Get WMI SoC handle
2593  * @param wmi_soc: Pointer to wmi soc object
2594  * @param pdev_idx: pdev index
2595  *
2596  * return: Pointer to wmi handle or NULL on failure
2597  */
2598 void *wmi_unified_get_pdev_handle(struct wmi_soc *soc, uint32_t pdev_idx)
2599 {
2600 	struct wmi_unified *wmi_handle;
2601 
2602 	if (pdev_idx >= WMI_MAX_RADIOS)
2603 		return NULL;
2604 
2605 	if (!soc->wmi_pdev[pdev_idx]) {
2606 		wmi_handle =
2607 			(struct wmi_unified *) qdf_mem_malloc(
2608 					sizeof(struct wmi_unified));
2609 		if (!wmi_handle)
2610 			return NULL;
2611 
2612 		wmi_handle->scn_handle = soc->scn_handle;
2613 		wmi_handle->event_id = soc->event_id;
2614 		wmi_handle->event_handler = soc->event_handler;
2615 		wmi_handle->ctx = soc->ctx;
2616 		wmi_handle->ops = soc->ops;
2617 		qdf_spinlock_create(&wmi_handle->eventq_lock);
2618 		qdf_nbuf_queue_init(&wmi_handle->event_queue);
2619 
2620 		qdf_create_work(0, &wmi_handle->rx_event_work,
2621 				wmi_rx_event_work, wmi_handle);
2622 		wmi_handle->wmi_rx_work_queue =
2623 			qdf_alloc_unbound_workqueue("wmi_rx_event_work_queue");
2624 		if (!wmi_handle->wmi_rx_work_queue) {
2625 			WMI_LOGE("failed to create wmi_rx_event_work_queue");
2626 			goto error;
2627 		}
2628 		wmi_handle->wmi_events = soc->wmi_events;
2629 		wmi_handle->services = soc->services;
2630 		wmi_handle->soc = soc;
2631 		wmi_handle->cmd_pdev_id_map = soc->cmd_pdev_id_map;
2632 		wmi_handle->evt_pdev_id_map = soc->evt_pdev_id_map;
2633 		wmi_interface_logging_init(wmi_handle, pdev_idx);
2634 		qdf_atomic_init(&wmi_handle->pending_cmds);
2635 		qdf_atomic_init(&wmi_handle->is_target_suspended);
2636 		wmi_handle->target_type = soc->target_type;
2637 		wmi_handle->wmi_max_cmds = soc->wmi_max_cmds;
2638 
2639 		soc->wmi_pdev[pdev_idx] = wmi_handle;
2640 	} else
2641 		wmi_handle = soc->wmi_pdev[pdev_idx];
2642 
2643 	wmi_handle->wmi_stopinprogress = 0;
2644 	wmi_handle->wmi_endpoint_id = soc->wmi_endpoint_id[pdev_idx];
2645 	wmi_handle->htc_handle = soc->htc_handle;
2646 	wmi_handle->max_msg_len = soc->max_msg_len[pdev_idx];
2647 
2648 	return wmi_handle;
2649 
2650 error:
2651 	qdf_mem_free(wmi_handle);
2652 
2653 	return NULL;
2654 }
2655 qdf_export_symbol(wmi_unified_get_pdev_handle);
2656 
2657 static void (*wmi_attach_register[WMI_MAX_TARGET_TYPE])(wmi_unified_t);
2658 
2659 void wmi_unified_register_module(enum wmi_target_type target_type,
2660 			void (*wmi_attach)(wmi_unified_t wmi_handle))
2661 {
2662 	if (target_type < WMI_MAX_TARGET_TYPE)
2663 		wmi_attach_register[target_type] = wmi_attach;
2664 
2665 	return;
2666 }
2667 qdf_export_symbol(wmi_unified_register_module);
2668 
2669 /**
2670  * wmi_wbuff_register() - register wmi with wbuff
2671  * @wmi_handle: handle to wmi
2672  *
2673  * @Return: void
2674  */
2675 static void wmi_wbuff_register(struct wmi_unified *wmi_handle)
2676 {
2677 	struct wbuff_alloc_request wbuff_alloc[4];
2678 
2679 	wbuff_alloc[0].slot = WBUFF_POOL_0;
2680 	wbuff_alloc[0].size = WMI_WBUFF_POOL_0_SIZE;
2681 	wbuff_alloc[1].slot = WBUFF_POOL_1;
2682 	wbuff_alloc[1].size = WMI_WBUFF_POOL_1_SIZE;
2683 	wbuff_alloc[2].slot = WBUFF_POOL_2;
2684 	wbuff_alloc[2].size = WMI_WBUFF_POOL_2_SIZE;
2685 	wbuff_alloc[3].slot = WBUFF_POOL_3;
2686 	wbuff_alloc[3].size = WMI_WBUFF_POOL_3_SIZE;
2687 
2688 	wmi_handle->wbuff_handle = wbuff_module_register(wbuff_alloc, 4,
2689 							 WMI_MIN_HEAD_ROOM, 4);
2690 }
2691 
2692 /**
2693  * wmi_wbuff_deregister() - deregister wmi with wbuff
2694  * @wmi_handle: handle to wmi
2695  *
2696  * @Return: void
2697  */
2698 static inline void wmi_wbuff_deregister(struct wmi_unified *wmi_handle)
2699 {
2700 	wbuff_module_deregister(wmi_handle->wbuff_handle);
2701 	wmi_handle->wbuff_handle = NULL;
2702 }
2703 
2704 /**
2705  * wmi_unified_attach() -  attach for unified WMI
2706  * @scn_handle: handle to SCN
2707  * @osdev: OS device context
2708  * @target_type: TLV or not-TLV based target
2709  * @use_cookie: cookie based allocation enabled/disabled
2710  * @ops: umac rx callbacks
2711  * @psoc: objmgr psoc
2712  *
2713  * @Return: wmi handle.
2714  */
2715 void *wmi_unified_attach(void *scn_handle,
2716 			 struct wmi_unified_attach_params *param)
2717 {
2718 	struct wmi_unified *wmi_handle;
2719 	struct wmi_soc *soc;
2720 
2721 	soc = (struct wmi_soc *) qdf_mem_malloc(sizeof(struct wmi_soc));
2722 	if (!soc)
2723 		return NULL;
2724 
2725 	wmi_handle =
2726 		(struct wmi_unified *) qdf_mem_malloc(
2727 			sizeof(struct wmi_unified));
2728 	if (!wmi_handle) {
2729 		qdf_mem_free(soc);
2730 		return NULL;
2731 	}
2732 	wmi_handle->soc = soc;
2733 	wmi_handle->soc->soc_idx = param->soc_id;
2734 	wmi_handle->soc->is_async_ep = param->is_async_ep;
2735 	wmi_handle->event_id = soc->event_id;
2736 	wmi_handle->event_handler = soc->event_handler;
2737 	wmi_handle->ctx = soc->ctx;
2738 	wmi_handle->wmi_events = soc->wmi_events;
2739 	wmi_handle->services = soc->services;
2740 	wmi_handle->scn_handle = scn_handle;
2741 	wmi_handle->cmd_pdev_id_map = soc->cmd_pdev_id_map;
2742 	wmi_handle->evt_pdev_id_map = soc->evt_pdev_id_map;
2743 	soc->scn_handle = scn_handle;
2744 	qdf_atomic_init(&wmi_handle->pending_cmds);
2745 	qdf_atomic_init(&wmi_handle->is_target_suspended);
2746 	qdf_atomic_init(&wmi_handle->num_stats_over_qmi);
2747 	wmi_runtime_pm_init(wmi_handle);
2748 	qdf_spinlock_create(&wmi_handle->eventq_lock);
2749 	qdf_nbuf_queue_init(&wmi_handle->event_queue);
2750 	qdf_create_work(0, &wmi_handle->rx_event_work,
2751 			wmi_rx_event_work, wmi_handle);
2752 	wmi_handle->wmi_rx_work_queue =
2753 		qdf_alloc_unbound_workqueue("wmi_rx_event_work_queue");
2754 	if (!wmi_handle->wmi_rx_work_queue) {
2755 		WMI_LOGE("failed to create wmi_rx_event_work_queue");
2756 		goto error;
2757 	}
2758 	wmi_interface_logging_init(wmi_handle, WMI_HOST_PDEV_ID_0);
2759 	wmi_handle->target_type = param->target_type;
2760 	soc->target_type = param->target_type;
2761 
2762 	if (param->target_type >= WMI_MAX_TARGET_TYPE)
2763 		goto error;
2764 
2765 	if (wmi_attach_register[param->target_type]) {
2766 		wmi_attach_register[param->target_type](wmi_handle);
2767 	} else {
2768 		WMI_LOGE("wmi attach is not registered");
2769 		goto error;
2770 	}
2771 	/* Assign target cookie capablity */
2772 	wmi_handle->use_cookie = param->use_cookie;
2773 	wmi_handle->osdev = param->osdev;
2774 	wmi_handle->wmi_stopinprogress = 0;
2775 	wmi_handle->wmi_max_cmds = param->max_commands;
2776 	soc->wmi_max_cmds = param->max_commands;
2777 	/* Increase the ref count once refcount infra is present */
2778 	soc->wmi_psoc = param->psoc;
2779 	qdf_spinlock_create(&soc->ctx_lock);
2780 
2781 	soc->ops = wmi_handle->ops;
2782 	soc->wmi_pdev[0] = wmi_handle;
2783 	if (wmi_ext_dbgfs_init(wmi_handle) != QDF_STATUS_SUCCESS)
2784 		WMI_LOGE("failed to initialize wmi extended debugfs");
2785 
2786 	wmi_wbuff_register(wmi_handle);
2787 
2788 	return wmi_handle;
2789 
2790 error:
2791 	qdf_mem_free(soc);
2792 	qdf_mem_free(wmi_handle);
2793 
2794 	return NULL;
2795 }
2796 
2797 /**
2798  * wmi_unified_detach() -  detach for unified WMI
2799  *
2800  * @wmi_handle  : handle to wmi.
2801  *
2802  * @Return: none.
2803  */
2804 void wmi_unified_detach(struct wmi_unified *wmi_handle)
2805 {
2806 	wmi_buf_t buf;
2807 	struct wmi_soc *soc;
2808 	uint8_t i;
2809 
2810 	wmi_wbuff_deregister(wmi_handle);
2811 
2812 	wmi_ext_dbgfs_deinit(wmi_handle);
2813 
2814 	soc = wmi_handle->soc;
2815 	for (i = 0; i < WMI_MAX_RADIOS; i++) {
2816 		if (soc->wmi_pdev[i]) {
2817 			qdf_flush_workqueue(0,
2818 				soc->wmi_pdev[i]->wmi_rx_work_queue);
2819 			qdf_destroy_workqueue(0,
2820 				soc->wmi_pdev[i]->wmi_rx_work_queue);
2821 			wmi_debugfs_remove(soc->wmi_pdev[i]);
2822 			buf = qdf_nbuf_queue_remove(
2823 					&soc->wmi_pdev[i]->event_queue);
2824 			while (buf) {
2825 				qdf_nbuf_free(buf);
2826 				buf = qdf_nbuf_queue_remove(
2827 						&soc->wmi_pdev[i]->event_queue);
2828 			}
2829 
2830 			wmi_log_buffer_free(soc->wmi_pdev[i]);
2831 
2832 			/* Free events logs list */
2833 			if (soc->wmi_pdev[i]->events_logs_list)
2834 				qdf_mem_free(
2835 					soc->wmi_pdev[i]->events_logs_list);
2836 
2837 			qdf_spinlock_destroy(&soc->wmi_pdev[i]->eventq_lock);
2838 			qdf_mem_free(soc->wmi_pdev[i]);
2839 		}
2840 	}
2841 	qdf_spinlock_destroy(&soc->ctx_lock);
2842 
2843 	if (soc->wmi_service_bitmap) {
2844 		qdf_mem_free(soc->wmi_service_bitmap);
2845 		soc->wmi_service_bitmap = NULL;
2846 	}
2847 
2848 	if (soc->wmi_ext_service_bitmap) {
2849 		qdf_mem_free(soc->wmi_ext_service_bitmap);
2850 		soc->wmi_ext_service_bitmap = NULL;
2851 	}
2852 
2853 	/* Decrease the ref count once refcount infra is present */
2854 	soc->wmi_psoc = NULL;
2855 	qdf_mem_free(soc);
2856 }
2857 
2858 /**
2859  * wmi_unified_remove_work() - detach for WMI work
2860  * @wmi_handle: handle to WMI
2861  *
2862  * A function that does not fully detach WMI, but just remove work
2863  * queue items associated with it. This is used to make sure that
2864  * before any other processing code that may destroy related contexts
2865  * (HTC, etc), work queue processing on WMI has already been stopped.
2866  *
2867  * Return: None
2868  */
2869 void
2870 wmi_unified_remove_work(struct wmi_unified *wmi_handle)
2871 {
2872 	wmi_buf_t buf;
2873 
2874 	qdf_flush_workqueue(0, wmi_handle->wmi_rx_work_queue);
2875 	qdf_spin_lock_bh(&wmi_handle->eventq_lock);
2876 	buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue);
2877 	while (buf) {
2878 		qdf_nbuf_free(buf);
2879 		buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue);
2880 	}
2881 	qdf_spin_unlock_bh(&wmi_handle->eventq_lock);
2882 }
2883 
2884 /**
2885  * wmi_htc_tx_complete() - Process htc tx completion
2886  *
2887  * @ctx: handle to wmi
2888  * @htc_packet: pointer to htc packet
2889  *
2890  * @Return: none.
2891  */
2892 static void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt)
2893 {
2894 	struct wmi_soc *soc = (struct wmi_soc *) ctx;
2895 	wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt);
2896 	u_int8_t *buf_ptr;
2897 	u_int32_t len;
2898 	struct wmi_unified *wmi_handle;
2899 #ifdef WMI_INTERFACE_EVENT_LOGGING
2900 	uint32_t cmd_id;
2901 #endif
2902 
2903 	ASSERT(wmi_cmd_buf);
2904 	wmi_handle = wmi_get_pdev_ep(soc, htc_pkt->Endpoint);
2905 	if (!wmi_handle) {
2906 		WMI_LOGE("%s: Unable to get wmi handle\n", __func__);
2907 		QDF_ASSERT(0);
2908 		return;
2909 	}
2910 #ifdef WMI_INTERFACE_EVENT_LOGGING
2911 	if (wmi_handle && wmi_handle->log_info.wmi_logging_enable) {
2912 		cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf),
2913 				WMI_CMD_HDR, COMMANDID);
2914 
2915 	qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock);
2916 	/* Record 16 bytes of WMI cmd tx complete data
2917 	- exclude TLV and WMI headers */
2918 	if (wmi_handle->ops->is_management_record(cmd_id)) {
2919 		WMI_MGMT_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
2920 			qdf_nbuf_data(wmi_cmd_buf) +
2921 			wmi_handle->soc->buf_offset_command);
2922 	} else {
2923 		WMI_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id,
2924 			qdf_nbuf_data(wmi_cmd_buf) +
2925 			wmi_handle->soc->buf_offset_command);
2926 	}
2927 
2928 	qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock);
2929 	}
2930 #endif
2931 	buf_ptr = (u_int8_t *) wmi_buf_data(wmi_cmd_buf);
2932 	len = qdf_nbuf_len(wmi_cmd_buf);
2933 	qdf_mem_zero(buf_ptr, len);
2934 	wmi_buf_free(wmi_cmd_buf);
2935 	qdf_mem_free(htc_pkt);
2936 	qdf_atomic_dec(&wmi_handle->pending_cmds);
2937 }
2938 
2939 #ifdef FEATURE_RUNTIME_PM
2940 /**
2941  * wmi_htc_log_pkt() - Print information of WMI command from HTC packet
2942  *
2943  * @ctx: handle of WMI context
2944  * @htc_pkt: handle of HTC packet
2945  *
2946  * @Return: none
2947  */
2948 static void wmi_htc_log_pkt(void *ctx, HTC_PACKET *htc_pkt)
2949 {
2950 	wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt);
2951 	uint32_t cmd_id;
2952 
2953 	ASSERT(wmi_cmd_buf);
2954 	cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf), WMI_CMD_HDR,
2955 			       COMMANDID);
2956 
2957 	WMI_LOGD("WMI command from HTC packet: %s, ID: %d\n",
2958 		 wmi_id_to_name(cmd_id), cmd_id);
2959 }
2960 #else
2961 static void wmi_htc_log_pkt(void *ctx, HTC_PACKET *htc_pkt)
2962 {
2963 }
2964 #endif
2965 
2966 /**
2967  * wmi_connect_pdev_htc_service() -  WMI API to get connect to HTC service
2968  *
2969  * @wmi_handle: handle to WMI.
2970  * @pdev_idx: Pdev index
2971  *
2972  * @Return: QDF_STATUS
2973  */
2974 static QDF_STATUS wmi_connect_pdev_htc_service(struct wmi_soc *soc,
2975 					       uint32_t pdev_idx)
2976 {
2977 	QDF_STATUS status;
2978 	struct htc_service_connect_resp response;
2979 	struct htc_service_connect_req connect;
2980 
2981 	OS_MEMZERO(&connect, sizeof(connect));
2982 	OS_MEMZERO(&response, sizeof(response));
2983 
2984 	/* meta data is unused for now */
2985 	connect.pMetaData = NULL;
2986 	connect.MetaDataLength = 0;
2987 	/* these fields are the same for all service endpoints */
2988 	connect.EpCallbacks.pContext = soc;
2989 	connect.EpCallbacks.EpTxCompleteMultiple =
2990 		NULL /* Control path completion ar6000_tx_complete */;
2991 	connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */;
2992 	connect.EpCallbacks.EpRecvRefill = NULL /* ar6000_rx_refill */;
2993 	connect.EpCallbacks.EpSendFull = NULL /* ar6000_tx_queue_full */;
2994 	connect.EpCallbacks.EpTxComplete =
2995 		wmi_htc_tx_complete /* ar6000_tx_queue_full */;
2996 	connect.EpCallbacks.ep_log_pkt = wmi_htc_log_pkt;
2997 
2998 	/* connect to control service */
2999 	connect.service_id = soc->svc_ids[pdev_idx];
3000 	status = htc_connect_service(soc->htc_handle, &connect, &response);
3001 
3002 	if (QDF_IS_STATUS_ERROR(status)) {
3003 		WMI_LOGE("Failed to connect to WMI CONTROL service status:%d\n",
3004 			 status);
3005 		return status;
3006 	}
3007 
3008 	if (soc->is_async_ep)
3009 		htc_set_async_ep(soc->htc_handle, response.Endpoint, true);
3010 
3011 	soc->wmi_endpoint_id[pdev_idx] = response.Endpoint;
3012 	soc->max_msg_len[pdev_idx] = response.MaxMsgLength;
3013 
3014 	return QDF_STATUS_SUCCESS;
3015 }
3016 
3017 QDF_STATUS
3018 wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle,
3019 				HTC_HANDLE htc_handle)
3020 {
3021 	uint32_t i;
3022 	uint8_t wmi_ep_count;
3023 
3024 	wmi_handle->soc->htc_handle = htc_handle;
3025 
3026 	wmi_ep_count = htc_get_wmi_endpoint_count(htc_handle);
3027 	if (wmi_ep_count > WMI_MAX_RADIOS)
3028 		return QDF_STATUS_E_FAULT;
3029 
3030 	for (i = 0; i < wmi_ep_count; i++)
3031 		wmi_connect_pdev_htc_service(wmi_handle->soc, i);
3032 
3033 	wmi_handle->htc_handle = htc_handle;
3034 	wmi_handle->wmi_endpoint_id = wmi_handle->soc->wmi_endpoint_id[0];
3035 	wmi_handle->max_msg_len = wmi_handle->soc->max_msg_len[0];
3036 
3037 	return QDF_STATUS_SUCCESS;
3038 }
3039 
3040 /**
3041  * wmi_get_host_credits() -  WMI API to get updated host_credits
3042  *
3043  * @wmi_handle: handle to WMI.
3044  *
3045  * @Return: updated host_credits.
3046  */
3047 int wmi_get_host_credits(wmi_unified_t wmi_handle)
3048 {
3049 	int host_credits = 0;
3050 
3051 	htc_get_control_endpoint_tx_host_credits(wmi_handle->htc_handle,
3052 						 &host_credits);
3053 	return host_credits;
3054 }
3055 
3056 /**
3057  * wmi_get_pending_cmds() - WMI API to get WMI Pending Commands in the HTC
3058  *                          queue
3059  *
3060  * @wmi_handle: handle to WMI.
3061  *
3062  * @Return: Pending Commands in the HTC queue.
3063  */
3064 int wmi_get_pending_cmds(wmi_unified_t wmi_handle)
3065 {
3066 	return qdf_atomic_read(&wmi_handle->pending_cmds);
3067 }
3068 
3069 /**
3070  * wmi_set_target_suspend() -  WMI API to set target suspend state
3071  *
3072  * @wmi_handle: handle to WMI.
3073  * @val: suspend state boolean.
3074  *
3075  * @Return: none.
3076  */
3077 void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val)
3078 {
3079 	qdf_atomic_set(&wmi_handle->is_target_suspended, val);
3080 }
3081 
3082 /**
3083  * wmi_is_target_suspended() - WMI API to check target suspend state
3084  * @wmi_handle: handle to WMI.
3085  *
3086  * WMI API to check target suspend state
3087  *
3088  * Return: true if target is suspended, else false.
3089  */
3090 bool wmi_is_target_suspended(struct wmi_unified *wmi_handle)
3091 {
3092 	return qdf_atomic_read(&wmi_handle->is_target_suspended);
3093 }
3094 
3095 /**
3096  * WMI API to set crash injection state
3097  * @param wmi_handle:	handle to WMI.
3098  * @param val:		crash injection state boolean.
3099  */
3100 void wmi_tag_crash_inject(wmi_unified_t wmi_handle, A_BOOL flag)
3101 {
3102 	wmi_handle->tag_crash_inject = flag;
3103 }
3104 
3105 /**
3106  * WMI API to set bus suspend state
3107  * @param wmi_handle:	handle to WMI.
3108  * @param val:		suspend state boolean.
3109  */
3110 void wmi_set_is_wow_bus_suspended(wmi_unified_t wmi_handle, A_BOOL val)
3111 {
3112 	qdf_atomic_set(&wmi_handle->is_wow_bus_suspended, val);
3113 }
3114 
3115 void wmi_set_tgt_assert(wmi_unified_t wmi_handle, bool val)
3116 {
3117 	wmi_handle->tgt_force_assert_enable = val;
3118 }
3119 
3120 /**
3121  * wmi_stop() - generic function to block unified WMI command
3122  * @wmi_handle: handle to WMI.
3123  *
3124  * @Return: success always.
3125  */
3126 int
3127 wmi_stop(wmi_unified_t wmi_handle)
3128 {
3129 	QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO,
3130 		  "WMI Stop");
3131 	wmi_handle->wmi_stopinprogress = 1;
3132 	return 0;
3133 }
3134 
3135 /**
3136  * wmi_start() - generic function to allow unified WMI command
3137  * @wmi_handle: handle to WMI.
3138  *
3139  * @Return: success always.
3140  */
3141 int
3142 wmi_start(wmi_unified_t wmi_handle)
3143 {
3144 	QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO,
3145 		  "WMI Start");
3146 	wmi_handle->wmi_stopinprogress = 0;
3147 	return 0;
3148 }
3149 
3150 /**
3151  * API to flush all the previous packets  associated with the wmi endpoint
3152  *
3153  * @param wmi_handle      : handle to WMI.
3154  */
3155 void
3156 wmi_flush_endpoint(wmi_unified_t wmi_handle)
3157 {
3158 	htc_flush_endpoint(wmi_handle->htc_handle,
3159 		wmi_handle->wmi_endpoint_id, 0);
3160 }
3161 qdf_export_symbol(wmi_flush_endpoint);
3162 
3163 /**
3164  * wmi_pdev_id_conversion_enable() - API to enable pdev_id conversion in WMI
3165  *                     By default pdev_id conversion is not done in WMI.
3166  *                     This API can be used enable conversion in WMI.
3167  * @param wmi_handle   : handle to WMI
3168  * @param pdev_map     : pointer to pdev_map
3169  * @size               : size of pdev_id_map
3170  * Return none
3171  */
3172 void wmi_pdev_id_conversion_enable(wmi_unified_t wmi_handle,
3173 				   uint32_t *pdev_id_map, uint8_t size)
3174 {
3175 	if (wmi_handle->target_type == WMI_TLV_TARGET)
3176 		wmi_handle->ops->wmi_pdev_id_conversion_enable(wmi_handle,
3177 							       pdev_id_map,
3178 							       size);
3179 }
3180