xref: /wlan-dirver/qca-wifi-host-cmn/target_if/cp_stats/src/target_if_cp_stats.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
1 /*
2  * Copyright (c) 2018, 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
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: target_if_cp_stats.c
22  *
23  * This file provide definition for APIs registered through lmac Tx Ops
24  */
25 
26 #include <qdf_mem.h>
27 #include <qdf_status.h>
28 #include <target_if_cp_stats.h>
29 #include <wmi_unified_priv.h>
30 #include <wmi_unified_param.h>
31 #include <target_if.h>
32 #include <wlan_tgt_def_config.h>
33 #include <wmi_unified_api.h>
34 #include <wlan_osif_priv.h>
35 #include <wlan_cp_stats_utils_api.h>
36 #include <wlan_objmgr_peer_obj.h>
37 #ifdef WLAN_FEATURE_MIB_STATS
38 #include <wlan_cp_stats_mc_defs.h>
39 #endif
40 #include "cp_stats/core/src/wlan_cp_stats_defs.h"
41 #include "cdp_txrx_cmn_struct.h"
42 #include "cdp_txrx_ctrl.h"
43 #include "cp_stats/core/src/wlan_cp_stats_comp_handler.h"
44 
45 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
46 
47 uint32_t get_infra_cp_stats_id(enum infra_cp_stats_id type)
48 {
49 	switch (type) {
50 	case TYPE_REQ_CTRL_PATH_PDEV_TX_STAT:
51 		return WMI_REQUEST_CTRL_PATH_PDEV_TX_STAT;
52 	case TYPE_REQ_CTRL_PATH_VDEV_EXTD_STAT:
53 		return WMI_REQUEST_CTRL_PATH_VDEV_EXTD_STAT;
54 	case TYPE_REQ_CTRL_PATH_MEM_STAT:
55 		return WMI_REQUEST_CTRL_PATH_MEM_STAT;
56 	case TYPE_REQ_CTRL_PATH_TWT_STAT:
57 		return WMI_REQUEST_CTRL_PATH_TWT_STAT;
58 	case TYPE_REQ_CTRL_PATH_BMISS_STAT:
59 		return WMI_REQUEST_CTRL_PATH_BMISS_STAT;
60 	default:
61 		return -EINVAL;
62 	}
63 }
64 
65 uint32_t get_infra_cp_stats_action(enum infra_cp_stats_action action)
66 {
67 	switch (action) {
68 	case ACTION_REQ_CTRL_PATH_STAT_GET:
69 		return WMI_REQUEST_CTRL_PATH_STAT_GET;
70 	case ACTION_REQ_CTRL_PATH_STAT_RESET:
71 		return WMI_REQUEST_CTRL_PATH_STAT_RESET;
72 	case ACTION_REQ_CTRL_PATH_STAT_START:
73 		return WMI_REQUEST_CTRL_PATH_STAT_START;
74 	case ACTION_REQ_CTRL_PATH_STAT_STOP:
75 		return WMI_REQUEST_CTRL_PATH_STAT_STOP;
76 	default:
77 		return -EINVAL;
78 	}
79 }
80 
81 #ifdef WLAN_SUPPORT_TWT
82 /**
83  * target_if_infra_cp_stats_twt_event_free() - Free event buffer
84  * @ev: pointer to infra cp stats event structure
85  *
86  * Return: None
87  */
88 static
89 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev)
90 {
91 	qdf_mem_free(ev->twt_infra_cp_stats);
92 	ev->twt_infra_cp_stats = NULL;
93 }
94 
95 /**
96  * target_if_infra_cp_stats_twt_event_alloc() - Allocate event buffer for TWT
97  * parameters
98  * @ev: pointer to infra cp stats event structure
99  *
100  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on
101  * failure
102  */
103 static QDF_STATUS
104 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev)
105 {
106 	ev->twt_infra_cp_stats =
107 			qdf_mem_malloc(sizeof(*ev->twt_infra_cp_stats) *
108 			INFRA_CP_STATS_MAX_RESP_TWT_DIALOG_ID);
109 	if (!ev->twt_infra_cp_stats) {
110 		cp_stats_err("mem alloc failed for ev.twt_infra_cp_stats");
111 		return QDF_STATUS_E_NOMEM;
112 	}
113 
114 	return QDF_STATUS_SUCCESS;
115 }
116 
117 #else
118 static inline
119 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev)
120 {
121 }
122 
123 static inline QDF_STATUS
124 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev)
125 {
126 	return QDF_STATUS_SUCCESS;
127 }
128 
129 static inline
130 void target_if_infra_cp_stats_free_stats_event(struct infra_cp_stats_event *ev)
131 {
132 }
133 #endif /* WLAN_SUPPORT_TWT */
134 
135 #ifdef CONFIG_WLAN_BMISS
136 
137 /**
138  * target_if_infra_cp_stats_bmiss_event_free() - Free event buffer
139  * @ev: pointer to infra cp stats event structure
140  *
141  * Return: None
142  */
143 static
144 void target_if_infra_cp_stats_bmiss_event_free(struct infra_cp_stats_event *ev)
145 {
146 	qdf_mem_free(ev->bmiss_infra_cp_stats);
147 	ev->bmiss_infra_cp_stats = NULL;
148 }
149 
150 /**
151  * target_if_infra_cp_stats_bmiss_event_alloc() - Allocate buffer for bmiss
152  * parameters
153  * @ev: pointer to infra cp stats event structure
154  *
155  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on
156  * failure
157  */
158 static QDF_STATUS
159 target_if_infra_cp_stats_bmiss_event_alloc(struct infra_cp_stats_event *ev)
160 {
161 	ev->bmiss_infra_cp_stats =
162 	qdf_mem_malloc(sizeof(*ev->bmiss_infra_cp_stats));
163 	if (!ev->bmiss_infra_cp_stats) {
164 		cp_stats_err("mem alloc failed for ev.bmiss_infra_cp_stats");
165 		return QDF_STATUS_E_NOMEM;
166 	}
167 
168 	return QDF_STATUS_SUCCESS;
169 }
170 #else
171 
172 static inline
173 void target_if_infra_cp_stats_bmiss_event_free(struct infra_cp_stats_event *ev)
174 {
175 }
176 
177 static inline QDF_STATUS
178 target_if_infra_cp_stats_bmiss_event_alloc(struct infra_cp_stats_event *ev)
179 {
180 	return QDF_STATUS_SUCCESS;
181 }
182 #endif /* CONFIG_WLAN_BMISS */
183 
184 /**
185  * target_if_infra_cp_stats_event_free() - Free event buffer
186  * @ev: pointer to infra cp stats event structure
187  *
188  * Return : None
189  */
190 static
191 void target_if_infra_cp_stats_event_free(struct infra_cp_stats_event *ev)
192 {
193 	target_if_infra_cp_stats_twt_event_free(ev);
194 	target_if_infra_cp_stats_bmiss_event_free(ev);
195 }
196 
197 /**
198  * target_if_infra_cp_stats_event_alloc() - Allocate buffer for event
199  * parameters
200  * @ev: pointer to infra cp stats event structure
201  *
202  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on
203  * failure
204  */
205 static QDF_STATUS
206 target_if_infra_cp_stats_event_alloc(struct infra_cp_stats_event *ev)
207 {
208 	QDF_STATUS status;
209 
210 	status = target_if_infra_cp_stats_twt_event_alloc(ev);
211 	if (status)
212 		return QDF_STATUS_E_NOMEM;
213 
214 	status = target_if_infra_cp_stats_bmiss_event_alloc(ev);
215 	if (status)
216 		return QDF_STATUS_E_NOMEM;
217 
218 	return QDF_STATUS_SUCCESS;
219 }
220 
221 /**
222  * target_if_extract_infra_cp_stats_event() - Extract data from stats event
223  * @wmi_hdl: WMI Handle
224  * @data: pointer to event data buffer from firmware
225  * @data_len: length of the data buffer
226  * @ev: pointer of output structure to be filled with extracted values
227  *
228  * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes
229  * on failure
230  */
231 static QDF_STATUS
232 target_if_extract_infra_cp_stats_event(struct wmi_unified *wmi_hdl,
233 				       uint8_t *data, uint32_t data_len,
234 				       struct infra_cp_stats_event *ev)
235 {
236 	QDF_STATUS status;
237 	uint32_t more_flag = 0;
238 
239 	status = wmi_unified_extract_cp_stats_more_pending(wmi_hdl, data,
240 							   &more_flag);
241 
242 	status = wmi_unified_extract_infra_cp_stats(wmi_hdl, data,
243 						    data_len, ev);
244 
245 	cp_stats_debug("request_id %d", ev->request_id);
246 
247 	return QDF_STATUS_SUCCESS;
248 }
249 
250 /**
251  * target_if_infra_cp_stats_event_handler() - Handle
252  * wmi_pdev_cp_fwstats_eventid
253  * @scn: opaque scn handle
254  * @data: event buffer received from fw
255  * @datalen: length of event buffer
256  *
257  * Return: 0 for success or non zero error codes for failure
258  */
259 static
260 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data,
261 					   uint32_t datalen)
262 {
263 	QDF_STATUS status;
264 	struct infra_cp_stats_event ev = {0};
265 	struct wlan_objmgr_psoc *psoc;
266 	struct wmi_unified *wmi_handle;
267 	struct wlan_lmac_if_cp_stats_rx_ops *rx_ops;
268 
269 	cp_stats_debug("Enter");
270 
271 	if (!scn || !data) {
272 		cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data);
273 		return -EINVAL;
274 	}
275 
276 	psoc = target_if_get_psoc_from_scn_hdl(scn);
277 	if (!psoc) {
278 		cp_stats_err("null psoc");
279 		return -EINVAL;
280 	}
281 
282 	rx_ops = target_if_cp_stats_get_rx_ops(psoc);
283 	if (!rx_ops || !rx_ops->process_stats_event) {
284 		cp_stats_err("callback not registered");
285 		return -EINVAL;
286 	}
287 
288 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
289 	if (!wmi_handle) {
290 		cp_stats_err("wmi_handle is null");
291 		return -EINVAL;
292 	}
293 	status = target_if_infra_cp_stats_event_alloc(&ev);
294 	if (QDF_IS_STATUS_ERROR(status)) {
295 		cp_stats_err("Alloc event mem failed");
296 		goto end;
297 	}
298 
299 	status = target_if_extract_infra_cp_stats_event(wmi_handle, data,
300 							datalen, &ev);
301 	if (QDF_IS_STATUS_ERROR(status)) {
302 		cp_stats_err("extract event failed");
303 		goto end;
304 	}
305 
306 	status = rx_ops->process_infra_stats_event(psoc, &ev);
307 
308 end:
309 	target_if_infra_cp_stats_event_free(&ev);
310 	return qdf_status_to_os_return(status);
311 }
312 #else
313 static
314 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data,
315 					   uint32_t datalen)
316 {
317 	return 0;
318 }
319 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
320 
321 #if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED)
322 static int
323 target_if_twt_session_params_event_handler(ol_scn_t scn,
324 					   uint8_t *evt_buf,
325 					   uint32_t evt_data_len)
326 {
327 	struct wlan_objmgr_psoc *psoc;
328 	struct wlan_objmgr_peer *peer_obj;
329 	struct wmi_unified *wmi_hdl;
330 	struct twt_session_stats_info twt_params;
331 	struct twt_session_stats_event_param params = {0};
332 	struct peer_cp_stats *peer_cp_stats;
333 	int i;
334 	QDF_STATUS status;
335 	uint32_t ev;
336 	cdp_config_param_type val = {0};
337 	ol_txrx_soc_handle soc_txrx_handle;
338 	struct wlan_lmac_if_rx_ops *rx_ops;
339 
340 	TARGET_IF_ENTER();
341 
342 	if (!scn || !evt_buf) {
343 		target_if_err("scn: 0x%pK, evt_buf: 0x%pK", scn, evt_buf);
344 		return -EINVAL;
345 	}
346 
347 	psoc = target_if_get_psoc_from_scn_hdl(scn);
348 	if (!psoc) {
349 		target_if_err("psoc object is null!");
350 		return -EINVAL;
351 	}
352 
353 	soc_txrx_handle = wlan_psoc_get_dp_handle(psoc);
354 	if (!soc_txrx_handle)
355 		return -EINVAL;
356 
357 	wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc);
358 	if (!wmi_hdl) {
359 		target_if_err("wmi_handle is null!");
360 		return -EINVAL;
361 	}
362 
363 	rx_ops = wlan_psoc_get_lmac_if_rxops(psoc);
364 	if (!rx_ops) {
365 		target_if_err("No valid twt session stats rx ops");
366 		return -EINVAL;
367 	}
368 
369 	status = wmi_extract_twt_session_stats_event(wmi_hdl, evt_buf, &params);
370 	if (QDF_IS_STATUS_ERROR(status)) {
371 		target_if_err("Could not extract twt session stats event");
372 		return qdf_status_to_os_return(status);
373 	}
374 
375 	if (params.num_sessions > WLAN_MAX_TWT_SESSIONS_PER_PEER) {
376 		target_if_err("Number of twt sessions exceeded, num:%d max:%d",
377 			      params.num_sessions, WLAN_MAX_TWT_SESSIONS_PER_PEER);
378 		return -EINVAL;
379 	}
380 
381 	for (i = 0; i < params.num_sessions; i++) {
382 		status = wmi_extract_twt_session_stats_data(wmi_hdl, evt_buf,
383 							    &params,
384 							    &twt_params, i);
385 
386 		if (QDF_IS_STATUS_ERROR(status)) {
387 			target_if_err("Unable to extract twt params for idx %d",
388 				      i);
389 			return -EINVAL;
390 		}
391 		peer_obj = wlan_objmgr_get_peer_by_mac(psoc,
392 						twt_params.peer_mac.bytes,
393 						WLAN_CP_STATS_ID);
394 		if (!peer_obj) {
395 			target_if_err("peer obj not found for "QDF_MAC_ADDR_FMT,
396 				      QDF_MAC_ADDR_REF(twt_params.peer_mac.bytes));
397 			continue;
398 		}
399 
400 		ev = twt_params.event_type;
401 		if (ev == HOST_TWT_SESSION_SETUP)
402 			val.cdp_peer_param_in_twt = 1;
403 		else if (ev == HOST_TWT_SESSION_TEARDOWN)
404 			val.cdp_peer_param_in_twt = 0;
405 
406 		cdp_txrx_set_peer_param(soc_txrx_handle, twt_params.vdev_id,
407 					twt_params.peer_mac.bytes,
408 					CDP_CONFIG_IN_TWT, val);
409 
410 		peer_cp_stats = wlan_cp_stats_get_peer_stats_obj(peer_obj);
411 		if (!peer_cp_stats) {
412 			target_if_err("peer_cp_stats is null");
413 			continue;
414 		}
415 
416 		wlan_cp_stats_peer_obj_lock(peer_cp_stats);
417 
418 		rx_ops->cp_stats_rx_ops.twt_get_session_param_resp(psoc,
419 								 &twt_params);
420 
421 		wlan_cp_stats_peer_obj_unlock(peer_cp_stats);
422 		wlan_objmgr_peer_release_ref(peer_obj, WLAN_CP_STATS_ID);
423 	}
424 	return 0;
425 }
426 
427 static QDF_STATUS
428 target_if_cp_stats_register_twt_session_event(struct wmi_unified *wmi_handle)
429 {
430 	QDF_STATUS ret_val;
431 
432 	ret_val = wmi_unified_register_event_handler(wmi_handle,
433 				wmi_twt_session_stats_event_id,
434 				target_if_twt_session_params_event_handler,
435 				WMI_RX_WORK_CTX);
436 
437 	return ret_val;
438 }
439 
440 static void
441 target_if_cp_stats_unregister_twt_session_event(struct wmi_unified *wmi_handle)
442 {
443 	wmi_unified_unregister_event_handler(wmi_handle,
444 					     wmi_twt_session_stats_event_id);
445 }
446 #else
447 static QDF_STATUS
448 target_if_cp_stats_register_twt_session_event(struct wmi_unified *wmi_handle)
449 {
450 	return QDF_STATUS_SUCCESS;
451 }
452 
453 static void
454 target_if_cp_stats_unregister_twt_session_event(struct wmi_unified *wmi_handle)
455 {
456 }
457 #endif /*  WLAN_SUPPORT_TWT && WLAN_TWT_CONV_SUPPORTED*/
458 
459 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
460 static QDF_STATUS
461 target_if_cp_stats_infra_register_event_handler(struct wlan_objmgr_psoc *psoc,
462 						struct wmi_unified *wmi_handle)
463 {
464 	QDF_STATUS ret_val;
465 
466 	if (!psoc) {
467 		cp_stats_err("PSOC is NULL!");
468 		return QDF_STATUS_E_INVAL;
469 	}
470 
471 	if (!wmi_handle) {
472 		cp_stats_err("wmi_handle is null");
473 		return QDF_STATUS_E_INVAL;
474 	}
475 
476 	ret_val = wmi_unified_register_event_handler(wmi_handle,
477 						     wmi_pdev_cp_fwstats_eventid,
478 						     target_if_infra_cp_stats_event_handler,
479 						     WMI_RX_WORK_CTX);
480 	if (QDF_IS_STATUS_ERROR(ret_val)) {
481 		cp_stats_err("Failed to register for pdev_cp_fwstats_event");
482 		return ret_val;
483 	}
484 
485 	return QDF_STATUS_SUCCESS;
486 }
487 #else
488 static QDF_STATUS
489 target_if_cp_stats_infra_register_event_handler(struct wlan_objmgr_psoc *psoc,
490 						struct wmi_unified *wmi_handle)
491 {
492 	return QDF_STATUS_SUCCESS;
493 }
494 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
495 
496 static QDF_STATUS
497 target_if_cp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc)
498 {
499 	struct wmi_unified *wmi_handle;
500 	QDF_STATUS ret_val;
501 
502 	if (!psoc) {
503 		cp_stats_err("PSOC is NULL!");
504 		return QDF_STATUS_E_INVAL;
505 	}
506 
507 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
508 	if (!wmi_handle) {
509 		cp_stats_err("wmi_handle is null");
510 		return QDF_STATUS_E_INVAL;
511 	}
512 
513 	ret_val = target_if_cp_stats_infra_register_event_handler(psoc,
514 								  wmi_handle);
515 	if (QDF_IS_STATUS_ERROR(ret_val)) {
516 		cp_stats_err("Failed to register for pdev_cp_fwstats_event");
517 		return ret_val;
518 	}
519 
520 	ret_val = target_if_cp_stats_register_twt_session_event(wmi_handle);
521 	if (QDF_IS_STATUS_ERROR(ret_val)) {
522 		cp_stats_err("Failed to register twt session stats event");
523 		return ret_val;
524 	}
525 
526 	return QDF_STATUS_SUCCESS;
527 }
528 
529 static QDF_STATUS
530 target_if_cp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc)
531 {
532 	struct wmi_unified *wmi_handle;
533 
534 	if (!psoc) {
535 		cp_stats_err("PSOC is NULL!");
536 		return QDF_STATUS_E_INVAL;
537 	}
538 
539 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
540 	if (!wmi_handle) {
541 		cp_stats_err("wmi_handle is null");
542 		return QDF_STATUS_E_INVAL;
543 	}
544 
545 	wmi_unified_unregister_event_handler(wmi_handle,
546 					     wmi_pdev_cp_fwstats_eventid);
547 	target_if_cp_stats_unregister_twt_session_event(wmi_handle);
548 	return QDF_STATUS_SUCCESS;
549 }
550 
551 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
552 /**
553  * target_if_infra_cp_stats_req() - API to send stats request to wmi
554  * @psoc: pointer to psoc object
555  * @req: pointer to object containing stats request parameters
556  *
557  * Return: QDF_STATUS_SUCCESS on success, else other qdf error values
558  */
559 static
560 QDF_STATUS target_if_infra_cp_stats_req(struct wlan_objmgr_psoc *psoc,
561 					struct infra_cp_stats_cmd_info *req)
562 
563 {
564 	struct wmi_unified *wmi_handle;
565 
566 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
567 	if (!wmi_handle) {
568 		cp_stats_err("wmi_handle is null.");
569 		return QDF_STATUS_E_NULL_VALUE;
570 	}
571 
572 	return wmi_unified_infra_cp_stats_request_send(wmi_handle, req);
573 }
574 
575 static void target_if_register_infra_cp_stats_txops(
576 				struct wlan_lmac_if_cp_stats_tx_ops *tx_ops)
577 {
578 	tx_ops->send_req_infra_cp_stats = target_if_infra_cp_stats_req;
579 }
580 #else
581 static void target_if_register_infra_cp_stats_txops(
582 				struct wlan_lmac_if_cp_stats_tx_ops *tx_ops)
583 {
584 }
585 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
586 
587 QDF_STATUS
588 target_if_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
589 {
590 	struct wlan_lmac_if_cp_stats_tx_ops *cp_stats_tx_ops;
591 
592 	if (!tx_ops) {
593 		cp_stats_err("lmac tx ops is NULL!");
594 		return QDF_STATUS_E_INVAL;
595 	}
596 
597 	cp_stats_tx_ops = &tx_ops->cp_stats_tx_ops;
598 	if (!cp_stats_tx_ops) {
599 		cp_stats_err("lmac tx ops is NULL!");
600 		return QDF_STATUS_E_FAILURE;
601 	}
602 	target_if_register_infra_cp_stats_txops(cp_stats_tx_ops);
603 
604 	cp_stats_tx_ops->cp_stats_attach =
605 		target_if_cp_stats_register_event_handler;
606 	cp_stats_tx_ops->cp_stats_detach =
607 		target_if_cp_stats_unregister_event_handler;
608 	cp_stats_tx_ops->cp_stats_legacy_attach =
609 		target_if_cp_stats_register_legacy_event_handler;
610 	cp_stats_tx_ops->cp_stats_legacy_detach =
611 		target_if_cp_stats_unregister_legacy_event_handler;
612 	return QDF_STATUS_SUCCESS;
613 }
614 
615