xref: /wlan-dirver/qca-wifi-host-cmn/dp/wifi3.0/monitor/2.0/dp_tx_mon_2.0.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "hal_be_hw_headers.h"
19 #include "dp_types.h"
20 #include "hal_be_tx.h"
21 #include "hal_api.h"
22 #include "qdf_trace.h"
23 #include "hal_be_api_mon.h"
24 #include "dp_internal.h"
25 #include "qdf_mem.h"   /* qdf_mem_malloc,free */
26 #include "dp_mon.h"
27 #include <dp_mon_2.0.h>
28 #include <dp_tx_mon_2.0.h>
29 #include <dp_be.h>
30 #include <hal_be_api_mon.h>
31 #include <dp_mon_filter_2.0.h>
32 #ifdef FEATURE_PERPKT_INFO
33 #include "dp_ratetable.h"
34 #endif
35 
36 #define MAX_TX_MONITOR_STUCK 50
37 
38 #ifdef TXMON_DEBUG
39 /*
40  * dp_tx_mon_debug_statu() - API to display tx monitor status
41  * @tx_mon_be - pointer to dp_pdev_tx_monitor_be
42  * @work_done - tx monitor work done
43  *
44  * Return: void
45  */
46 static inline void
47 dp_tx_mon_debug_status(struct dp_pdev_tx_monitor_be *tx_mon_be,
48 		       uint32_t work_done)
49 {
50 	if (tx_mon_be->mode && !work_done)
51 		tx_mon_be->stats.tx_mon_stuck++;
52 	else if (tx_mon_be->mode && work_done)
53 		tx_mon_be->stats.tx_mon_stuck = 0;
54 
55 	if (tx_mon_be->stats.tx_mon_stuck > MAX_TX_MONITOR_STUCK) {
56 		dp_mon_warn("Tx monitor block got stuck!!!!!");
57 		tx_mon_be->stats.tx_mon_stuck = 0;
58 		tx_mon_be->stats.total_tx_mon_stuck++;
59 	}
60 
61 	dp_mon_debug_rl("tx_ppdu_info[%u :D %u] STATUS[R %llu: F %llu] PKT_BUF[R %llu: F %llu : P %llu : S %llu]",
62 			tx_mon_be->tx_ppdu_info_list_depth,
63 			tx_mon_be->defer_ppdu_info_list_depth,
64 			tx_mon_be->stats.status_buf_recv,
65 			tx_mon_be->stats.status_buf_free,
66 			tx_mon_be->stats.pkt_buf_recv,
67 			tx_mon_be->stats.pkt_buf_free,
68 			tx_mon_be->stats.pkt_buf_processed,
69 			tx_mon_be->stats.pkt_buf_to_stack);
70 }
71 
72 #else
73 /*
74  * dp_tx_mon_debug_statu() - API to display tx monitor status
75  * @tx_mon_be - pointer to dp_pdev_tx_monitor_be
76  * @work_done - tx monitor work done
77  *
78  * Return: void
79  */
80 static inline void
81 dp_tx_mon_debug_status(struct dp_pdev_tx_monitor_be *tx_mon_be,
82 		       uint32_t work_done)
83 {
84 	if (tx_mon_be->mode && !work_done)
85 		tx_mon_be->stats.tx_mon_stuck++;
86 	else if (tx_mon_be->mode && work_done)
87 		tx_mon_be->stats.tx_mon_stuck = 0;
88 
89 	if (tx_mon_be->stats.tx_mon_stuck > MAX_TX_MONITOR_STUCK) {
90 		dp_mon_warn("Tx monitor block got stuck!!!!!");
91 		tx_mon_be->stats.tx_mon_stuck = 0;
92 		tx_mon_be->stats.total_tx_mon_stuck++;
93 	}
94 }
95 #endif
96 
97 static inline uint32_t
98 dp_tx_mon_srng_process_2_0(struct dp_soc *soc, struct dp_intr *int_ctx,
99 			   uint32_t mac_id, uint32_t quota)
100 {
101 	struct dp_pdev *pdev = dp_get_pdev_for_lmac_id(soc, mac_id);
102 	void *tx_mon_dst_ring_desc;
103 	hal_soc_handle_t hal_soc;
104 	void *mon_dst_srng;
105 	struct dp_mon_pdev *mon_pdev;
106 	struct dp_mon_pdev_be *mon_pdev_be;
107 	uint32_t work_done = 0;
108 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
109 	struct dp_mon_soc_be *mon_soc_be = dp_get_be_mon_soc_from_dp_mon_soc(mon_soc);
110 	struct dp_pdev_tx_monitor_be *tx_mon_be = NULL;
111 	struct dp_mon_desc_pool *tx_mon_desc_pool = &mon_soc_be->tx_desc_mon;
112 	struct dp_tx_mon_desc_list mon_desc_list;
113 	uint32_t replenish_cnt = 0;
114 
115 	if (!pdev) {
116 		dp_mon_err("%pK: pdev is null for mac_id = %d", soc, mac_id);
117 		return work_done;
118 	}
119 
120 	mon_pdev = pdev->monitor_pdev;
121 	mon_dst_srng = mon_soc_be->tx_mon_dst_ring[mac_id].hal_srng;
122 
123 	if (!mon_dst_srng || !hal_srng_initialized(mon_dst_srng)) {
124 		dp_mon_err("%pK: : HAL Monitor Destination Ring Init Failed -- %pK",
125 			   soc, mon_dst_srng);
126 		return work_done;
127 	}
128 
129 	mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
130 	if (qdf_unlikely(!mon_pdev_be))
131 		return work_done;
132 
133 	tx_mon_be = &mon_pdev_be->tx_monitor_be;
134 	hal_soc = soc->hal_soc;
135 
136 	qdf_assert((hal_soc && pdev));
137 
138 	qdf_spin_lock_bh(&mon_pdev->mon_lock);
139 	mon_desc_list.desc_list = NULL;
140 	mon_desc_list.tail = NULL;
141 	mon_desc_list.tx_mon_reap_cnt = 0;
142 
143 	if (qdf_unlikely(dp_srng_access_start(int_ctx, soc, mon_dst_srng))) {
144 		dp_mon_err("%s %d : HAL Mon Dest Ring access Failed -- %pK",
145 			   __func__, __LINE__, mon_dst_srng);
146 		qdf_spin_unlock_bh(&mon_pdev->mon_lock);
147 		return work_done;
148 	}
149 
150 	while (qdf_likely((tx_mon_dst_ring_desc =
151 		(void *)hal_srng_dst_peek(hal_soc, mon_dst_srng))
152 				&& quota--)) {
153 		struct hal_mon_desc hal_mon_tx_desc = {0};
154 		struct dp_mon_desc *mon_desc = NULL;
155 		qdf_frag_t status_frag = NULL;
156 		uint32_t end_offset = 0;
157 
158 		hal_be_get_mon_dest_status(soc->hal_soc,
159 					   tx_mon_dst_ring_desc,
160 					   &hal_mon_tx_desc);
161 
162 		if (hal_mon_tx_desc.empty_descriptor) {
163 			/* update stats counter */
164 			dp_mon_debug("P_ID:%d INIT:%d E_DESC:%d R_ID:%d L_CNT:%d  DROP[PPDU:%d MPDU:%d TLV:%d] E_O_PPDU:%d",
165 				    hal_mon_tx_desc.ppdu_id,
166 				    hal_mon_tx_desc.initiator,
167 				    hal_mon_tx_desc.empty_descriptor,
168 				    hal_mon_tx_desc.ring_id,
169 				    hal_mon_tx_desc.looping_count,
170 				    hal_mon_tx_desc.ppdu_drop_count,
171 				    hal_mon_tx_desc.mpdu_drop_count,
172 				    hal_mon_tx_desc.tlv_drop_count,
173 				    hal_mon_tx_desc.end_of_ppdu_dropped);
174 
175 			tx_mon_be->stats.ppdu_drop_cnt +=
176 				hal_mon_tx_desc.ppdu_drop_count;
177 			tx_mon_be->stats.mpdu_drop_cnt +=
178 				hal_mon_tx_desc.mpdu_drop_count;
179 			tx_mon_be->stats.tlv_drop_cnt +=
180 				hal_mon_tx_desc.tlv_drop_count;
181 			work_done++;
182 			hal_srng_dst_get_next(hal_soc, mon_dst_srng);
183 			continue;
184 		}
185 
186 		dp_mon_debug("P_ID:%d INIT:%d E_DESC:%d R_ID:%d L_CNT:%d BUF_ADDR: 0x%llx E_OFF: %d E_REA: %d",
187 			    hal_mon_tx_desc.ppdu_id,
188 			    hal_mon_tx_desc.initiator,
189 			    hal_mon_tx_desc.empty_descriptor,
190 			    hal_mon_tx_desc.ring_id,
191 			    hal_mon_tx_desc.looping_count,
192 			    hal_mon_tx_desc.buf_addr,
193 			    hal_mon_tx_desc.end_offset,
194 			    hal_mon_tx_desc.end_reason);
195 
196 		mon_desc = (struct dp_mon_desc *)(uintptr_t)(hal_mon_tx_desc.buf_addr);
197 		qdf_assert_always(mon_desc);
198 
199 		if (!mon_desc->unmapped) {
200 			qdf_mem_unmap_page(soc->osdev, mon_desc->paddr,
201 					   DP_MON_DATA_BUFFER_SIZE,
202 					   QDF_DMA_FROM_DEVICE);
203 			mon_desc->unmapped = 1;
204 		}
205 
206 		if (mon_desc->magic != DP_MON_DESC_MAGIC) {
207 			dp_mon_err("Invalid monitor descriptor");
208 			qdf_assert_always(0);
209 		}
210 
211 		end_offset = hal_mon_tx_desc.end_offset;
212 
213 		status_frag = (qdf_frag_t)(mon_desc->buf_addr);
214 		mon_desc->buf_addr = NULL;
215 		/* increment reap count */
216 		++mon_desc_list.tx_mon_reap_cnt;
217 
218 		/* add the mon_desc to free list */
219 		dp_mon_add_to_free_desc_list(&mon_desc_list.desc_list,
220 					     &mon_desc_list.tail, mon_desc);
221 
222 
223 		if (qdf_unlikely(!status_frag)) {
224 			dp_mon_debug("P_ID:%d INIT:%d E_DESC:%d R_ID:%d L_CNT:%d BUF_ADDR: 0x%llx E_OFF: %d E_REA: %d",
225 				     hal_mon_tx_desc.ppdu_id,
226 				     hal_mon_tx_desc.initiator,
227 				     hal_mon_tx_desc.empty_descriptor,
228 				     hal_mon_tx_desc.ring_id,
229 				     hal_mon_tx_desc.looping_count,
230 				     hal_mon_tx_desc.buf_addr,
231 				     hal_mon_tx_desc.end_offset,
232 				     hal_mon_tx_desc.end_reason);
233 
234 			work_done++;
235 			hal_srng_dst_get_next(hal_soc, mon_dst_srng);
236 			continue;
237 		}
238 
239 		tx_mon_be->stats.status_buf_recv++;
240 
241 		if ((hal_mon_tx_desc.end_reason == HAL_MON_FLUSH_DETECTED) ||
242 		    (hal_mon_tx_desc.end_reason == HAL_MON_PPDU_TRUNCATED)) {
243 			tx_mon_be->be_ppdu_id = hal_mon_tx_desc.ppdu_id;
244 
245 			dp_tx_mon_update_end_reason(mon_pdev,
246 						    hal_mon_tx_desc.ppdu_id,
247 						    hal_mon_tx_desc.end_reason);
248 			/* check and free packet buffer from status buffer */
249 			dp_tx_mon_status_free_packet_buf(pdev, status_frag,
250 							 end_offset,
251 							 &mon_desc_list);
252 
253 			tx_mon_be->stats.status_buf_free++;
254 			qdf_frag_free(status_frag);
255 
256 			work_done++;
257 			hal_srng_dst_get_next(hal_soc, mon_dst_srng);
258 			continue;
259 		}
260 
261 		dp_tx_mon_process_status_tlv(soc, pdev,
262 					     &hal_mon_tx_desc,
263 					     status_frag,
264 					     end_offset,
265 					     &mon_desc_list);
266 
267 		work_done++;
268 		hal_srng_dst_get_next(hal_soc, mon_dst_srng);
269 	}
270 	dp_srng_access_end(int_ctx, soc, mon_dst_srng);
271 
272 	if (mon_desc_list.tx_mon_reap_cnt) {
273 		dp_mon_buffers_replenish(soc, &mon_soc_be->tx_mon_buf_ring,
274 					 tx_mon_desc_pool,
275 					 mon_desc_list.tx_mon_reap_cnt,
276 					 &mon_desc_list.desc_list,
277 					 &mon_desc_list.tail,
278 					 &replenish_cnt);
279 	}
280 	qdf_spin_unlock_bh(&mon_pdev->mon_lock);
281 	dp_mon_debug("mac_id: %d, work_done:%d tx_monitor_reap_cnt:%d",
282 		     mac_id, work_done, mon_desc_list.tx_mon_reap_cnt);
283 
284 	tx_mon_be->stats.total_tx_mon_reap_cnt += mon_desc_list.tx_mon_reap_cnt;
285 	tx_mon_be->stats.totat_tx_mon_replenish_cnt += replenish_cnt;
286 	dp_tx_mon_debug_status(tx_mon_be, work_done);
287 
288 	return work_done;
289 }
290 
291 uint32_t
292 dp_tx_mon_process_2_0(struct dp_soc *soc, struct dp_intr *int_ctx,
293 		      uint32_t mac_id, uint32_t quota)
294 {
295 	uint32_t work_done;
296 
297 	work_done = dp_tx_mon_srng_process_2_0(soc, int_ctx, mac_id, quota);
298 
299 	return work_done;
300 }
301 
302 void
303 dp_tx_mon_buf_desc_pool_deinit(struct dp_soc *soc)
304 {
305 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
306 	struct dp_mon_soc_be *mon_soc_be =
307 		dp_get_be_mon_soc_from_dp_mon_soc(mon_soc);
308 
309 	dp_mon_desc_pool_deinit(&mon_soc_be->tx_desc_mon);
310 }
311 
312 QDF_STATUS
313 dp_tx_mon_buf_desc_pool_init(struct dp_soc *soc)
314 {
315 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
316 	struct dp_mon_soc_be *mon_soc_be =
317 		dp_get_be_mon_soc_from_dp_mon_soc(mon_soc);
318 	uint32_t num_entries;
319 
320 	num_entries =
321 		wlan_cfg_get_dp_soc_tx_mon_buf_ring_size(soc->wlan_cfg_ctx);
322 
323 	return dp_mon_desc_pool_init(&mon_soc_be->tx_desc_mon, num_entries);
324 }
325 
326 void dp_tx_mon_buf_desc_pool_free(struct dp_soc *soc)
327 {
328 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
329 	struct dp_mon_soc_be *mon_soc_be =
330 		dp_get_be_mon_soc_from_dp_mon_soc(mon_soc);
331 
332 	if (mon_soc_be)
333 		dp_mon_desc_pool_free(&mon_soc_be->tx_desc_mon);
334 }
335 
336 QDF_STATUS
337 dp_tx_mon_buf_desc_pool_alloc(struct dp_soc *soc)
338 {
339 	struct dp_srng *mon_buf_ring;
340 	struct dp_mon_desc_pool *tx_mon_desc_pool;
341 	int entries;
342 	struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx;
343 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
344 	struct dp_mon_soc_be *mon_soc_be =
345 		dp_get_be_mon_soc_from_dp_mon_soc(mon_soc);
346 
347 	soc_cfg_ctx = soc->wlan_cfg_ctx;
348 
349 	entries = wlan_cfg_get_dp_soc_tx_mon_buf_ring_size(soc_cfg_ctx);
350 
351 	mon_buf_ring = &mon_soc_be->tx_mon_buf_ring;
352 
353 	tx_mon_desc_pool = &mon_soc_be->tx_desc_mon;
354 
355 	qdf_print("%s:%d tx mon buf desc pool entries: %d", __func__, __LINE__, entries);
356 	return dp_mon_desc_pool_alloc(entries, tx_mon_desc_pool);
357 }
358 
359 void
360 dp_tx_mon_buffers_free(struct dp_soc *soc)
361 {
362 	struct dp_mon_desc_pool *tx_mon_desc_pool;
363 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
364 	struct dp_mon_soc_be *mon_soc_be =
365 		dp_get_be_mon_soc_from_dp_mon_soc(mon_soc);
366 
367 	tx_mon_desc_pool = &mon_soc_be->tx_desc_mon;
368 
369 	dp_mon_pool_frag_unmap_and_free(soc, tx_mon_desc_pool);
370 }
371 
372 QDF_STATUS
373 dp_tx_mon_buffers_alloc(struct dp_soc *soc, uint32_t size)
374 {
375 	struct dp_srng *mon_buf_ring;
376 	struct dp_mon_desc_pool *tx_mon_desc_pool;
377 	union dp_mon_desc_list_elem_t *desc_list = NULL;
378 	union dp_mon_desc_list_elem_t *tail = NULL;
379 	struct dp_mon_soc *mon_soc = soc->monitor_soc;
380 	struct dp_mon_soc_be *mon_soc_be =
381 		dp_get_be_mon_soc_from_dp_mon_soc(mon_soc);
382 
383 	mon_buf_ring = &mon_soc_be->tx_mon_buf_ring;
384 
385 	tx_mon_desc_pool = &mon_soc_be->tx_desc_mon;
386 
387 	return dp_mon_buffers_replenish(soc, mon_buf_ring,
388 					tx_mon_desc_pool,
389 					size,
390 					&desc_list, &tail, NULL);
391 }
392 
393 #ifdef WLAN_TX_PKT_CAPTURE_ENH_BE
394 
395 /*
396  * dp_tx_mon_nbuf_get_num_frag() - get total number of fragments
397  * @buf: Network buf instance
398  *
399  * Return: number of fragments
400  */
401 static inline
402 uint32_t dp_tx_mon_nbuf_get_num_frag(qdf_nbuf_t nbuf)
403 {
404 	uint32_t num_frag = 0;
405 
406 	if (qdf_unlikely(!nbuf))
407 		return num_frag;
408 
409 	num_frag = qdf_nbuf_get_nr_frags_in_fraglist(nbuf);
410 
411 	return num_frag;
412 }
413 
414 /*
415  * dp_tx_mon_free_usr_mpduq() - API to free user mpduq
416  * @tx_ppdu_info - pointer to tx_ppdu_info
417  * @usr_idx - user index
418  * @tx_mon_be - pointer to tx capture be
419  *
420  * Return: void
421  */
422 void dp_tx_mon_free_usr_mpduq(struct dp_tx_ppdu_info *tx_ppdu_info,
423 			      uint8_t usr_idx,
424 			      struct dp_pdev_tx_monitor_be *tx_mon_be)
425 {
426 	qdf_nbuf_queue_t *mpdu_q;
427 	uint32_t num_frag = 0;
428 	qdf_nbuf_t buf = NULL;
429 
430 	if (qdf_unlikely(!tx_ppdu_info))
431 		return;
432 
433 	mpdu_q = &TXMON_PPDU_USR(tx_ppdu_info, usr_idx, mpdu_q);
434 
435 	while ((buf = qdf_nbuf_queue_remove(mpdu_q)) != NULL) {
436 		num_frag += dp_tx_mon_nbuf_get_num_frag(buf);
437 		qdf_nbuf_free(buf);
438 	}
439 	tx_mon_be->stats.pkt_buf_free += num_frag;
440 }
441 
442 /*
443  * dp_tx_mon_free_ppdu_info() - API to free dp_tx_ppdu_info
444  * @tx_ppdu_info - pointer to tx_ppdu_info
445  * @tx_mon_be - pointer to tx capture be
446  *
447  * Return: void
448  */
449 void dp_tx_mon_free_ppdu_info(struct dp_tx_ppdu_info *tx_ppdu_info,
450 			      struct dp_pdev_tx_monitor_be *tx_mon_be)
451 {
452 	uint32_t user = 0;
453 
454 	for (; user < TXMON_PPDU_HAL(tx_ppdu_info, num_users); user++) {
455 		qdf_nbuf_queue_t *mpdu_q;
456 		uint32_t num_frag = 0;
457 		qdf_nbuf_t buf = NULL;
458 
459 		mpdu_q = &TXMON_PPDU_USR(tx_ppdu_info, user, mpdu_q);
460 
461 		while ((buf = qdf_nbuf_queue_remove(mpdu_q)) != NULL) {
462 			num_frag += dp_tx_mon_nbuf_get_num_frag(buf);
463 			qdf_nbuf_free(buf);
464 		}
465 		tx_mon_be->stats.pkt_buf_free += num_frag;
466 	}
467 
468 	TXMON_PPDU_HAL(tx_ppdu_info, is_used) = 0;
469 	qdf_mem_free(tx_ppdu_info);
470 }
471 
472 /*
473  * dp_tx_mon_get_ppdu_info() - API to allocate dp_tx_ppdu_info
474  * @pdev - pdev handle
475  * @type - type of ppdu_info data or protection
476  * @num_user - number user in a ppdu_info
477  * @ppdu_id - ppdu_id number
478  *
479  * Return: pointer to dp_tx_ppdu_info
480  */
481 struct dp_tx_ppdu_info *dp_tx_mon_get_ppdu_info(struct dp_pdev *pdev,
482 						enum tx_ppdu_info_type type,
483 						uint8_t num_user,
484 						uint32_t ppdu_id)
485 {
486 	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
487 	struct dp_mon_pdev_be *mon_pdev_be =
488 			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
489 	struct dp_pdev_tx_monitor_be *tx_mon_be =
490 			&mon_pdev_be->tx_monitor_be;
491 	struct dp_tx_ppdu_info *tx_ppdu_info;
492 	size_t sz_ppdu_info = 0;
493 	uint8_t i;
494 
495 	/* allocate new tx_ppdu_info */
496 	sz_ppdu_info = (sizeof(struct dp_tx_ppdu_info) +
497 			(sizeof(struct mon_rx_user_status) * num_user));
498 
499 	tx_ppdu_info = (struct dp_tx_ppdu_info *)qdf_mem_malloc(sz_ppdu_info);
500 	if (!tx_ppdu_info) {
501 		dp_mon_err("allocation of tx_ppdu_info type[%d] failed!!!",
502 			   type);
503 		return NULL;
504 	}
505 
506 	TXMON_PPDU_HAL(tx_ppdu_info, is_used) = 0;
507 	TXMON_PPDU_HAL(tx_ppdu_info, num_users) = num_user;
508 	TXMON_PPDU_HAL(tx_ppdu_info, ppdu_id) = ppdu_id;
509 	tx_ppdu_info->ppdu_id = ppdu_id;
510 
511 	for (i = 0; i < num_user; i++) {
512 		qdf_nbuf_queue_t *mpdu_q;
513 
514 		mpdu_q = &TXMON_PPDU_USR(tx_ppdu_info, i, mpdu_q);
515 		qdf_nbuf_queue_init(mpdu_q);
516 	}
517 
518 	/* assign tx_ppdu_info to monitor pdev for reference */
519 	if (type == TX_PROT_PPDU_INFO) {
520 		tx_mon_be->tx_prot_ppdu_info = tx_ppdu_info;
521 		TXMON_PPDU_HAL(tx_ppdu_info, is_data) = 0;
522 	} else {
523 		tx_mon_be->tx_data_ppdu_info = tx_ppdu_info;
524 		TXMON_PPDU_HAL(tx_ppdu_info, is_data) = 1;
525 	}
526 
527 	return tx_ppdu_info;
528 }
529 
530 /*
531  * dp_print_pdev_tx_monitor_stats_2_0: print tx capture stats
532  * @pdev: DP PDEV handle
533  *
534  * return: void
535  */
536 void dp_print_pdev_tx_monitor_stats_2_0(struct dp_pdev *pdev)
537 {
538 	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
539 	struct dp_mon_pdev_be *mon_pdev_be =
540 			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
541 	struct dp_pdev_tx_monitor_be *tx_mon_be =
542 			&mon_pdev_be->tx_monitor_be;
543 	struct dp_tx_monitor_drop_stats stats = {0};
544 
545 	qdf_mem_copy(&stats, &tx_mon_be->stats,
546 		     sizeof(struct dp_tx_monitor_drop_stats));
547 
548 	/* TX monitor stats needed for beryllium */
549 	DP_PRINT_STATS("\n\tTX Capture BE stats mode[%d]:", tx_mon_be->mode);
550 	DP_PRINT_STATS("\tbuffer pending : %u", tx_mon_be->last_frag_q_idx);
551 	DP_PRINT_STATS("\treplenish count: %llu",
552 		       stats.totat_tx_mon_replenish_cnt);
553 	DP_PRINT_STATS("\treap count     : %llu", stats.total_tx_mon_reap_cnt);
554 	DP_PRINT_STATS("\tmonitor stuck  : %u", stats.total_tx_mon_stuck);
555 	DP_PRINT_STATS("\tStatus buffer");
556 	DP_PRINT_STATS("\t\treceived  : %llu", stats.status_buf_recv);
557 	DP_PRINT_STATS("\t\tfree      : %llu", stats.status_buf_free);
558 	DP_PRINT_STATS("\tPacket buffer");
559 	DP_PRINT_STATS("\t\treceived  : %llu", stats.pkt_buf_recv);
560 	DP_PRINT_STATS("\t\tfree      : %llu", stats.pkt_buf_free);
561 	DP_PRINT_STATS("\t\tprocessed : %llu", stats.pkt_buf_processed);
562 	DP_PRINT_STATS("\t\tto stack  : %llu", stats.pkt_buf_to_stack);
563 	DP_PRINT_STATS("\tppdu info");
564 	DP_PRINT_STATS("\t\tthreshold : %llu", stats.ppdu_info_drop_th);
565 	DP_PRINT_STATS("\t\tflush     : %llu", stats.ppdu_info_drop_flush);
566 	DP_PRINT_STATS("\t\ttruncated : %llu", stats.ppdu_info_drop_trunc);
567 	DP_PRINT_STATS("\tDrop stats");
568 	DP_PRINT_STATS("\t\tppdu drop : %llu", stats.ppdu_drop_cnt);
569 	DP_PRINT_STATS("\t\tmpdu drop : %llu", stats.mpdu_drop_cnt);
570 	DP_PRINT_STATS("\t\ttlv drop : %llu", stats.tlv_drop_cnt);
571 }
572 
573 /*
574  * dp_config_enh_tx_monitor_2_0()- API to enable/disable enhanced tx capture
575  * @pdev_handle: DP_PDEV handle
576  * @val: user provided value
577  *
578  * Return: QDF_STATUS
579  */
580 QDF_STATUS
581 dp_config_enh_tx_monitor_2_0(struct dp_pdev *pdev, uint8_t val)
582 {
583 	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
584 	struct dp_mon_pdev_be *mon_pdev_be =
585 			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
586 	struct dp_pdev_tx_monitor_be *tx_mon_be =
587 			&mon_pdev_be->tx_monitor_be;
588 
589 	switch (val) {
590 	case TX_MON_BE_DISABLE:
591 	{
592 		/* TODO: send HTT msg to configure TLV based on mode */
593 		tx_mon_be->mode = TX_MON_BE_DISABLE;
594 		mon_pdev_be->tx_mon_mode = 0;
595 		mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_64B;
596 		break;
597 	}
598 	case TX_MON_BE_FULL_CAPTURE:
599 	{
600 		/* TODO: send HTT msg to configure TLV based on mode */
601 		qdf_mem_zero(&tx_mon_be->stats,
602 			     sizeof(struct dp_tx_monitor_drop_stats));
603 		tx_mon_be->mode = TX_MON_BE_FULL_CAPTURE;
604 		mon_pdev_be->tx_mon_mode = 1;
605 		mon_pdev_be->tx_mon_filter_length = DEFAULT_DMA_LENGTH;
606 		break;
607 	}
608 	case TX_MON_BE_PEER_FILTER:
609 	{
610 		/* TODO: send HTT msg to configure TLV based on mode */
611 		tx_mon_be->mode = TX_MON_BE_PEER_FILTER;
612 		mon_pdev_be->tx_mon_mode = 2;
613 		mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_256B;
614 		break;
615 	}
616 	default:
617 	{
618 		/* TODO: do we need to set to disable ? */
619 		return QDF_STATUS_E_INVAL;
620 	}
621 	}
622 
623 	dp_mon_info("Tx monitor mode:%d mon_mode_flag:%d config_length:%d",
624 		    tx_mon_be->mode, mon_pdev_be->tx_mon_mode,
625 		    mon_pdev_be->tx_mon_filter_length);
626 
627 	dp_mon_filter_setup_tx_mon_mode(pdev);
628 	dp_tx_mon_filter_update(pdev);
629 
630 	return QDF_STATUS_SUCCESS;
631 }
632 
633 /*
634  * dp_peer_set_tx_capture_enabled_2_0() -  add tx monitor peer filter
635  * @pdev: Datapath PDEV handle
636  * @peer: Datapath PEER handle
637  * @is_tx_pkt_cap_enable: flag for tx capture enable/disable
638  * @peer_mac: peer mac address
639  *
640  * Return: status
641  */
642 QDF_STATUS dp_peer_set_tx_capture_enabled_2_0(struct dp_pdev *pdev_handle,
643 					      struct dp_peer *peer_handle,
644 					      uint8_t is_tx_pkt_cap_enable,
645 					      uint8_t *peer_mac)
646 {
647 	return QDF_STATUS_SUCCESS;
648 }
649 
650 #ifdef QCA_SUPPORT_LITE_MONITOR
651 static void dp_fill_lite_mon_vdev(struct cdp_tx_indication_info *tx_cap_info,
652 				  struct dp_mon_pdev_be *mon_pdev_be)
653 {
654 	struct dp_lite_mon_config *config;
655 	struct dp_vdev *lite_mon_vdev;
656 
657 	config = &mon_pdev_be->lite_mon_tx_config->tx_config;
658 	lite_mon_vdev = config->lite_mon_vdev;
659 
660 	if (lite_mon_vdev)
661 		tx_cap_info->osif_vdev = lite_mon_vdev->osif_vdev;
662 }
663 #else
664 static void dp_fill_lite_mon_vdev(struct cdp_tx_indication_info *tx_cap_info,
665 				  struct dp_mon_pdev_be *mon_pdev_be)
666 {
667 }
668 #endif
669 
670 /**
671  * dp_tx_mon_send_to_stack() - API to send to stack
672  * @pdev: pdev Handle
673  * @mpdu: pointer to mpdu
674  * @num_frag: number of frag in mpdu
675  *
676  * Return: void
677  */
678 static void
679 dp_tx_mon_send_to_stack(struct dp_pdev *pdev, qdf_nbuf_t mpdu,
680 			uint32_t num_frag)
681 {
682 	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
683 	struct dp_mon_pdev_be *mon_pdev_be =
684 			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
685 	struct dp_pdev_tx_monitor_be *tx_mon_be =
686 			&mon_pdev_be->tx_monitor_be;
687 	struct cdp_tx_indication_info tx_capture_info = {0};
688 
689 	tx_mon_be->stats.pkt_buf_to_stack += num_frag;
690 
691 	tx_capture_info.radiotap_done = 1;
692 	tx_capture_info.mpdu_nbuf = mpdu;
693 	if (!dp_lite_mon_is_tx_enabled(mon_pdev)) {
694 		dp_wdi_event_handler(WDI_EVENT_TX_PKT_CAPTURE,
695 				     pdev->soc,
696 				     &tx_capture_info,
697 				     HTT_INVALID_PEER,
698 				     WDI_NO_VAL,
699 				     pdev->pdev_id);
700 	} else {
701 		dp_fill_lite_mon_vdev(&tx_capture_info, mon_pdev_be);
702 		dp_wdi_event_handler(WDI_EVENT_LITE_MON_TX,
703 				     pdev->soc,
704 				     &tx_capture_info,
705 				     HTT_INVALID_PEER,
706 				     WDI_NO_VAL,
707 				     pdev->pdev_id);
708 	}
709 	if (tx_capture_info.mpdu_nbuf)
710 		qdf_nbuf_free(tx_capture_info.mpdu_nbuf);
711 }
712 
713 /**
714  * dp_tx_mon_send_per_usr_mpdu() - API to send per usr mpdu to stack
715  * @pdev: pdev Handle
716  * @ppdu_info: pointer to dp_tx_ppdu_info
717  * @user_id: current user index
718  *
719  * Return: void
720  */
721 static void
722 dp_tx_mon_send_per_usr_mpdu(struct dp_pdev *pdev,
723 			    struct dp_tx_ppdu_info *ppdu_info,
724 			    uint8_t user_idx)
725 {
726 	qdf_nbuf_queue_t *usr_mpdu_q = NULL;
727 	qdf_nbuf_t buf = NULL;
728 
729 	usr_mpdu_q = &TXMON_PPDU_USR(ppdu_info, user_idx, mpdu_q);
730 
731 	while ((buf = qdf_nbuf_queue_remove(usr_mpdu_q)) != NULL) {
732 		uint32_t num_frag = dp_tx_mon_nbuf_get_num_frag(buf);
733 
734 		ppdu_info->hal_txmon.rx_status.rx_user_status =
735 				&ppdu_info->hal_txmon.rx_user_status[user_idx];
736 
737 		qdf_nbuf_update_radiotap(&ppdu_info->hal_txmon.rx_status,
738 					 buf, qdf_nbuf_headroom(buf));
739 
740 		dp_tx_mon_send_to_stack(pdev, buf, num_frag);
741 	}
742 }
743 
744 /**
745  * dp_tx_mon_update_radiotap() - API to update radiotap information
746  * @pdev: pdev Handle
747  * @ppdu_info: pointer to dp_tx_ppdu_info
748  *
749  * Return: void
750  */
751 static void
752 dp_tx_mon_update_radiotap(struct dp_pdev *pdev,
753 			  struct dp_tx_ppdu_info *ppdu_info)
754 {
755 	uint32_t usr_idx = 0;
756 	uint32_t num_users = 0;
757 
758 	num_users = TXMON_PPDU_HAL(ppdu_info, num_users);
759 
760 	if (qdf_unlikely(TXMON_PPDU_COM(ppdu_info, chan_num) == 0))
761 		TXMON_PPDU_COM(ppdu_info, chan_num) =
762 				pdev->operating_channel.num;
763 
764 	if (qdf_unlikely(TXMON_PPDU_COM(ppdu_info, chan_freq) == 0))
765 		TXMON_PPDU_COM(ppdu_info, chan_freq) =
766 				pdev->operating_channel.freq;
767 
768 	for (usr_idx = 0; usr_idx < num_users; usr_idx++) {
769 		qdf_nbuf_queue_t *mpdu_q = NULL;
770 
771 		/* set AMPDU flag if number mpdu is more than 1 */
772 		mpdu_q = &TXMON_PPDU_USR(ppdu_info, usr_idx, mpdu_q);
773 		if (mpdu_q && (qdf_nbuf_queue_len(mpdu_q) > 1)) {
774 			TXMON_PPDU_COM(ppdu_info,
775 				       rs_flags) |= IEEE80211_AMPDU_FLAG;
776 			TXMON_PPDU_USR(ppdu_info, usr_idx, is_ampdu) = 1;
777 		}
778 
779 		if (qdf_unlikely(!TXMON_PPDU_COM(ppdu_info, rate))) {
780 			uint32_t rate = 0;
781 			uint32_t rix = 0;
782 			uint16_t ratecode = 0;
783 
784 			rate = dp_getrateindex(TXMON_PPDU_COM(ppdu_info, sgi),
785 					       TXMON_PPDU_USR(ppdu_info,
786 							      usr_idx, mcs),
787 					       TXMON_PPDU_COM(ppdu_info, nss),
788 					       TXMON_PPDU_COM(ppdu_info,
789 							      preamble_type),
790 					       TXMON_PPDU_COM(ppdu_info, bw),
791 					       0,
792 					       &rix, &ratecode);
793 
794 			/* update rate */
795 			TXMON_PPDU_COM(ppdu_info, rate) = rate;
796 		}
797 
798 		dp_tx_mon_send_per_usr_mpdu(pdev, ppdu_info, usr_idx);
799 	}
800 }
801 
802 /**
803  * dp_tx_mon_ppdu_process - Deferred PPDU stats handler
804  * @context: Opaque work context (PDEV)
805  *
806  * Return: none
807  */
808 void dp_tx_mon_ppdu_process(void *context)
809 {
810 	struct dp_pdev *pdev = (struct dp_pdev *)context;
811 	struct dp_mon_pdev *mon_pdev;
812 	struct dp_mon_pdev_be *mon_pdev_be;
813 	struct dp_tx_ppdu_info *defer_ppdu_info = NULL;
814 	struct dp_tx_ppdu_info *defer_ppdu_info_next = NULL;
815 	struct dp_pdev_tx_monitor_be *tx_mon_be;
816 
817 	/* sanity check */
818 	if (qdf_unlikely(!pdev))
819 		return;
820 
821 	mon_pdev = pdev->monitor_pdev;
822 
823 	if (qdf_unlikely(!mon_pdev))
824 		return;
825 
826 	mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
827 	if (qdf_unlikely(!mon_pdev_be))
828 		return;
829 
830 	tx_mon_be = &mon_pdev_be->tx_monitor_be;
831 	if (qdf_unlikely(TX_MON_BE_DISABLE == tx_mon_be->mode &&
832 			 !dp_lite_mon_is_tx_enabled(mon_pdev)))
833 		return;
834 
835 	/* take lock here */
836 	qdf_spin_lock_bh(&tx_mon_be->tx_mon_list_lock);
837 	STAILQ_CONCAT(&tx_mon_be->defer_tx_ppdu_info_queue,
838 		      &tx_mon_be->tx_ppdu_info_queue);
839 	tx_mon_be->defer_ppdu_info_list_depth +=
840 		tx_mon_be->tx_ppdu_info_list_depth;
841 	tx_mon_be->tx_ppdu_info_list_depth = 0;
842 	qdf_spin_unlock_bh(&tx_mon_be->tx_mon_list_lock);
843 
844 	STAILQ_FOREACH_SAFE(defer_ppdu_info,
845 			    &tx_mon_be->defer_tx_ppdu_info_queue,
846 			    tx_ppdu_info_queue_elem, defer_ppdu_info_next) {
847 		/* remove dp_tx_ppdu_info from the list */
848 		STAILQ_REMOVE(&tx_mon_be->defer_tx_ppdu_info_queue,
849 			      defer_ppdu_info,
850 			      dp_tx_ppdu_info,
851 			      tx_ppdu_info_queue_elem);
852 		tx_mon_be->defer_ppdu_info_list_depth--;
853 
854 		dp_tx_mon_update_radiotap(pdev, defer_ppdu_info);
855 
856 		/* free the ppdu_info */
857 		dp_tx_mon_free_ppdu_info(defer_ppdu_info, tx_mon_be);
858 		defer_ppdu_info = NULL;
859 	}
860 }
861 
862 /**
863  * dp_tx_ppdu_stats_attach_2_0 - Initialize Tx PPDU stats and enhanced capture
864  * @pdev: DP PDEV
865  *
866  * Return: none
867  */
868 void dp_tx_ppdu_stats_attach_2_0(struct dp_pdev *pdev)
869 {
870 	struct dp_mon_pdev *mon_pdev;
871 	struct dp_mon_pdev_be *mon_pdev_be;
872 	struct dp_pdev_tx_monitor_be *tx_mon_be;
873 
874 	if (qdf_unlikely(!pdev))
875 		return;
876 
877 	mon_pdev = pdev->monitor_pdev;
878 
879 	if (qdf_unlikely(!mon_pdev))
880 		return;
881 
882 	mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
883 	if (qdf_unlikely(!mon_pdev_be))
884 		return;
885 
886 	tx_mon_be = &mon_pdev_be->tx_monitor_be;
887 
888 	STAILQ_INIT(&tx_mon_be->tx_ppdu_info_queue);
889 	tx_mon_be->tx_ppdu_info_list_depth = 0;
890 
891 	STAILQ_INIT(&tx_mon_be->defer_tx_ppdu_info_queue);
892 	tx_mon_be->defer_ppdu_info_list_depth = 0;
893 
894 	qdf_spinlock_create(&tx_mon_be->tx_mon_list_lock);
895 	/* Work queue setup for TX MONITOR post handling */
896 	qdf_create_work(0, &tx_mon_be->post_ppdu_work,
897 			dp_tx_mon_ppdu_process, pdev);
898 
899 	tx_mon_be->post_ppdu_workqueue =
900 			qdf_alloc_unbound_workqueue("tx_mon_ppdu_work_queue");
901 }
902 
903 /**
904  * dp_tx_ppdu_stats_detach_be - Cleanup Tx PPDU stats and enhanced capture
905  * @pdev: DP PDEV
906  *
907  * Return: none
908  */
909 void dp_tx_ppdu_stats_detach_2_0(struct dp_pdev *pdev)
910 {
911 	struct dp_mon_pdev *mon_pdev;
912 	struct dp_mon_pdev_be *mon_pdev_be;
913 	struct dp_pdev_tx_monitor_be *tx_mon_be;
914 	struct dp_tx_ppdu_info *tx_ppdu_info = NULL;
915 	struct dp_tx_ppdu_info *tx_ppdu_info_next = NULL;
916 
917 	if (qdf_unlikely(!pdev))
918 		return;
919 
920 	mon_pdev = pdev->monitor_pdev;
921 
922 	if (qdf_unlikely(!mon_pdev))
923 		return;
924 
925 	mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
926 	if (qdf_unlikely(!mon_pdev_be))
927 		return;
928 
929 	tx_mon_be = &mon_pdev_be->tx_monitor_be;
930 	/* TODO: disable tx_monitor, to avoid further packet from HW */
931 	dp_monitor_config_enh_tx_capture(pdev, TX_MON_BE_DISABLE);
932 
933 	/* flush workqueue */
934 	qdf_flush_workqueue(0, tx_mon_be->post_ppdu_workqueue);
935 	qdf_destroy_workqueue(0, tx_mon_be->post_ppdu_workqueue);
936 
937 	/*
938 	 * TODO: iterate both tx_ppdu_info and defer_ppdu_info_list
939 	 * free the tx_ppdu_info and decrement depth
940 	 */
941 	qdf_spin_lock_bh(&tx_mon_be->tx_mon_list_lock);
942 	STAILQ_FOREACH_SAFE(tx_ppdu_info,
943 			    &tx_mon_be->tx_ppdu_info_queue,
944 			    tx_ppdu_info_queue_elem, tx_ppdu_info_next) {
945 		/* remove dp_tx_ppdu_info from the list */
946 		STAILQ_REMOVE(&tx_mon_be->tx_ppdu_info_queue, tx_ppdu_info,
947 			      dp_tx_ppdu_info, tx_ppdu_info_queue_elem);
948 		/* decrement list length */
949 		tx_mon_be->tx_ppdu_info_list_depth--;
950 		/* free tx_ppdu_info */
951 		dp_tx_mon_free_ppdu_info(tx_ppdu_info, tx_mon_be);
952 	}
953 	qdf_spin_unlock_bh(&tx_mon_be->tx_mon_list_lock);
954 
955 	qdf_spin_lock_bh(&tx_mon_be->tx_mon_list_lock);
956 	STAILQ_FOREACH_SAFE(tx_ppdu_info,
957 			    &tx_mon_be->defer_tx_ppdu_info_queue,
958 			    tx_ppdu_info_queue_elem, tx_ppdu_info_next) {
959 		/* remove dp_tx_ppdu_info from the list */
960 		STAILQ_REMOVE(&tx_mon_be->defer_tx_ppdu_info_queue,
961 			      tx_ppdu_info,
962 			      dp_tx_ppdu_info, tx_ppdu_info_queue_elem);
963 		/* decrement list length */
964 		tx_mon_be->defer_ppdu_info_list_depth--;
965 		/* free tx_ppdu_info */
966 		dp_tx_mon_free_ppdu_info(tx_ppdu_info, tx_mon_be);
967 	}
968 	qdf_spin_unlock_bh(&tx_mon_be->tx_mon_list_lock);
969 
970 	qdf_spinlock_destroy(&tx_mon_be->tx_mon_list_lock);
971 }
972 #endif /* WLAN_TX_PKT_CAPTURE_ENH_BE */
973 
974 #if (defined(WIFI_MONITOR_SUPPORT) && !defined(WLAN_TX_PKT_CAPTURE_ENH_BE))
975 /*
976  * dp_config_enh_tx_core_monitor_2_0()- API to validate core framework
977  * @pdev_handle: DP_PDEV handle
978  * @val: user provided value
979  *
980  * Return: QDF_STATUS
981  */
982 QDF_STATUS
983 dp_config_enh_tx_core_monitor_2_0(struct dp_pdev *pdev, uint8_t val)
984 {
985 	struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev;
986 	struct dp_mon_pdev_be *mon_pdev_be =
987 			dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev);
988 	struct dp_pdev_tx_monitor_be *tx_mon_be =
989 			&mon_pdev_be->tx_monitor_be;
990 
991 	switch (val) {
992 	case TX_MON_BE_FRM_WRK_DISABLE:
993 	{
994 		tx_mon_be->mode = val;
995 		mon_pdev_be->tx_mon_mode = 0;
996 		mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_64B;
997 		break;
998 	}
999 	case TX_MON_BE_FRM_WRK_FULL_CAPTURE:
1000 	{
1001 		tx_mon_be->mode = val;
1002 		qdf_mem_zero(&tx_mon_be->stats,
1003 			     sizeof(struct dp_tx_monitor_drop_stats));
1004 		tx_mon_be->mode = val;
1005 		mon_pdev_be->tx_mon_mode = 1;
1006 		mon_pdev_be->tx_mon_filter_length = DEFAULT_DMA_LENGTH;
1007 		break;
1008 	}
1009 	case TX_MON_BE_FRM_WRK_128B_CAPTURE:
1010 	{
1011 		tx_mon_be->mode = val;
1012 		mon_pdev_be->tx_mon_mode = 1;
1013 		mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_128B;
1014 		break;
1015 	}
1016 	default:
1017 	{
1018 		return QDF_STATUS_E_INVAL;
1019 	}
1020 	}
1021 
1022 	dp_mon_debug("Tx monitor mode:%d mon_mode_flag:%d config_length:%d",
1023 		    tx_mon_be->mode, mon_pdev_be->tx_mon_mode,
1024 		    mon_pdev_be->tx_mon_filter_length);
1025 
1026 	/* send HTT msg to configure TLV based on mode */
1027 	dp_mon_filter_setup_tx_mon_mode(pdev);
1028 	dp_tx_mon_filter_update(pdev);
1029 
1030 	return QDF_STATUS_SUCCESS;
1031 }
1032 #endif
1033