xref: /wlan-dirver/qca-wifi-host-cmn/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.c (revision 410a2ae521186f1b1da58f3a6b2b6789e2117a3c)
1 /*
2  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2024 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: wlan_cp_stats_om_handler.c
22  *
23  * This file provide definitions to APIs invoked on receiving common object
24  * respective create/destroy event notifications, which further
25  * (de)allocate cp specific objects and (de)attach to specific
26  * common object
27  */
28 #include "wlan_cp_stats_obj_mgr_handler.h"
29 #include "wlan_cp_stats_defs.h"
30 #include "wlan_cp_stats_ol_api.h"
31 #include <wlan_cp_stats_ucfg_api.h>
32 #include "wlan_cp_stats_utils_api.h"
33 #include <target_if_cp_stats.h>
34 #include <wlan_twt_public_structs.h>
35 #include <wlan_cp_stats_chipset_stats.h>
36 
37 #ifdef WLAN_CHIPSET_STATS
38 int wlan_cp_stats_cstats_qmi_event_handler(void *cb_ctx, uint16_t type,
39 					   void *event, int event_len)
40 {
41 	if (type == CSTATS_QMI_EVENT_TYPE)
42 		wlan_cstats_fw_stats(event_len, event);
43 
44 	return 0;
45 }
46 
47 static void
48 wlan_cp_stats_cstats_register_qmi_event_handler(struct cp_stats_context *csc)
49 {
50 	QDF_STATUS status;
51 
52 	status =
53 	    qdf_reg_qmi_indication(csc, wlan_cp_stats_cstats_qmi_event_handler);
54 
55 	if (QDF_IS_STATUS_ERROR(status))
56 		cp_stats_err("cstats QMI evt handler registration failed");
57 }
58 
59 bool wlan_cp_stats_get_chipset_stats_enable(struct wlan_objmgr_psoc *psoc)
60 {
61 	struct cp_stats_context *csc;
62 
63 	csc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
64 						    WLAN_UMAC_COMP_CP_STATS);
65 	if (!csc) {
66 		cp_stats_err("CP Stats Context is NULL");
67 		return false;
68 	}
69 
70 	return csc->host_params.chipset_stats_enable;
71 }
72 
73 static void wlan_cp_stats_enable_init_cstats(struct wlan_objmgr_pdev *pdev)
74 {
75 	bool fw_support = false;
76 	struct wlan_objmgr_psoc *psoc;
77 	struct wlan_lmac_if_cp_stats_tx_ops *tx_ops;
78 	struct cp_stats_context *csc;
79 
80 	psoc = wlan_pdev_get_psoc(pdev);
81 	if (!psoc) {
82 		cp_stats_err("PSOC is NULL");
83 		return;
84 	}
85 
86 	csc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
87 						    WLAN_UMAC_COMP_CP_STATS);
88 	if (!csc) {
89 		cp_stats_err("CP Stats Context is NULL");
90 		return;
91 	}
92 
93 	target_if_cp_stats_is_service_cstats_enabled(psoc, &fw_support);
94 
95 	/* If feature is enabled in INI and FW also supports this feature
96 	 * Then send WMI_PDEV_PARAM_ENABLE_CHIPSET_LOGGING to enable
97 	 * the functionality in FW
98 	 */
99 	if (!fw_support || !wlan_cp_stats_get_chipset_stats_enable(psoc)) {
100 		cp_stats_debug("Chipset Stats is disabled");
101 		return;
102 	}
103 
104 	tx_ops = target_if_cp_stats_get_tx_ops(psoc);
105 	if (!tx_ops) {
106 		cp_stats_err("could not get tx_ops");
107 		return;
108 	}
109 
110 	if (!tx_ops->send_cstats_enable) {
111 		cp_stats_err("could not get send_cstats_enable");
112 		return;
113 	}
114 
115 	wlan_cp_stats_cstats_register_qmi_event_handler(csc);
116 
117 	/* Send WMI PDEV command to enable chipset stats with SOC ID
118 	 * a valid pdev id for this command will not work. This command
119 	 * always expects SOC ID to be sent. Chipset Stats logging enabled
120 	 * for all the PDEVs.
121 	 */
122 	tx_ops->send_cstats_enable(psoc, CSTATS_QMI_EVENT_TYPE,
123 				   WMI_PDEV_ID_SOC);
124 }
125 #else
126 static inline
127 void wlan_cp_stats_enable_init_cstats(struct wlan_objmgr_pdev *pdev)
128 {
129 }
130 #endif /* WLAN_CHIPSET_STATS */
131 
132 QDF_STATUS
133 wlan_cp_stats_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
134 {
135 	WLAN_DEV_TYPE dev_type;
136 	struct cp_stats_context *csc = NULL;
137 	struct psoc_cp_stats *psoc_cs = NULL;
138 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
139 
140 	if (!psoc) {
141 		cp_stats_err("PSOC is NULL");
142 		status = QDF_STATUS_E_INVAL;
143 		goto wlan_cp_stats_psoc_obj_create_handler_return;
144 	}
145 
146 	csc = qdf_mem_malloc(sizeof(*csc));
147 	if (!csc) {
148 		status = QDF_STATUS_E_NOMEM;
149 		goto wlan_cp_stats_psoc_obj_create_handler_return;
150 	}
151 
152 	csc->psoc_obj = psoc;
153 	dev_type = wlan_objmgr_psoc_get_dev_type(csc->psoc_obj);
154 	if (dev_type == WLAN_DEV_INVALID) {
155 		cp_stats_err("Failed to init cp stats ctx, bad device type");
156 		status = QDF_STATUS_E_INVAL;
157 		goto wlan_cp_stats_psoc_obj_create_handler_return;
158 	} else if (WLAN_DEV_OL == dev_type) {
159 		csc->cp_stats_ctx_init = wlan_cp_stats_ctx_init_ol;
160 		csc->cp_stats_ctx_deinit = wlan_cp_stats_ctx_deinit_ol;
161 	}
162 
163 	if (QDF_STATUS_SUCCESS != csc->cp_stats_ctx_init(csc)) {
164 		cp_stats_err("Failed to init global ctx call back handlers");
165 		goto wlan_cp_stats_psoc_obj_create_handler_return;
166 	}
167 
168 	psoc_cs = qdf_mem_malloc(sizeof(*psoc_cs));
169 	if (!psoc_cs) {
170 		status = QDF_STATUS_E_NOMEM;
171 		goto wlan_cp_stats_psoc_obj_create_handler_return;
172 	}
173 
174 	psoc_cs->psoc_obj = psoc;
175 	csc->psoc_cs = psoc_cs;
176 	if (csc->cp_stats_psoc_obj_init) {
177 		if (QDF_STATUS_SUCCESS !=
178 				csc->cp_stats_psoc_obj_init(psoc_cs)) {
179 			cp_stats_err("Failed to initialize psoc handlers");
180 			goto wlan_cp_stats_psoc_obj_create_handler_return;
181 		}
182 	}
183 
184 	status = wlan_objmgr_psoc_component_obj_attach(psoc,
185 						       WLAN_UMAC_COMP_CP_STATS,
186 						       csc,
187 						       QDF_STATUS_SUCCESS);
188 
189 wlan_cp_stats_psoc_obj_create_handler_return:
190 	if (QDF_IS_STATUS_ERROR(status)) {
191 		if (csc) {
192 			if (csc->cp_stats_psoc_obj_deinit && psoc_cs)
193 				csc->cp_stats_psoc_obj_deinit(psoc_cs);
194 
195 			if (csc->psoc_cs) {
196 				qdf_mem_free(csc->psoc_cs);
197 				csc->psoc_cs = NULL;
198 			}
199 
200 			if (csc->cp_stats_ctx_deinit)
201 				csc->cp_stats_ctx_deinit(csc);
202 
203 			qdf_mem_free(csc);
204 			csc = NULL;
205 		}
206 		return status;
207 	}
208 
209 	cp_stats_debug("cp stats context attach at psoc");
210 	return status;
211 }
212 
213 QDF_STATUS
214 wlan_cp_stats_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg)
215 {
216 	struct cp_stats_context *csc;
217 
218 	if (!psoc) {
219 		cp_stats_err("PSOC is NULL");
220 		return QDF_STATUS_E_NOMEM;
221 	}
222 	csc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
223 						    WLAN_UMAC_COMP_CP_STATS);
224 	if (!csc) {
225 		cp_stats_err("cp_stats context is NULL!");
226 		return QDF_STATUS_E_INVAL;
227 	}
228 
229 	wlan_objmgr_psoc_component_obj_detach(psoc,
230 					      WLAN_UMAC_COMP_CP_STATS, csc);
231 	if (csc->cp_stats_psoc_obj_deinit)
232 		csc->cp_stats_psoc_obj_deinit(csc->psoc_cs);
233 	qdf_mem_free(csc->psoc_cs);
234 	if (csc->cp_stats_ctx_deinit)
235 		csc->cp_stats_ctx_deinit(csc);
236 	qdf_mem_free(csc);
237 
238 	cp_stats_debug("cp stats context detached at psoc");
239 	return QDF_STATUS_SUCCESS;
240 }
241 
242 QDF_STATUS
243 wlan_cp_stats_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
244 {
245 	struct cp_stats_context *csc = NULL;
246 	struct pdev_cp_stats *pdev_cs = NULL;
247 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
248 
249 	if (!pdev) {
250 		cp_stats_err("PDEV is NULL");
251 		status = QDF_STATUS_E_INVAL;
252 		goto wlan_cp_stats_pdev_obj_create_handler_return;
253 	}
254 
255 	pdev_cs = qdf_mem_malloc(sizeof(*pdev_cs));
256 	if (!pdev_cs) {
257 		status = QDF_STATUS_E_NOMEM;
258 		goto wlan_cp_stats_pdev_obj_create_handler_return;
259 	}
260 	csc = wlan_cp_stats_ctx_get_from_pdev(pdev);
261 	if (!csc) {
262 		cp_stats_err("cp_stats context is NULL!");
263 		status = QDF_STATUS_E_INVAL;
264 		goto wlan_cp_stats_pdev_obj_create_handler_return;
265 	}
266 	pdev_cs->pdev_obj = pdev;
267 	if (csc->cp_stats_pdev_obj_init) {
268 		if (QDF_STATUS_SUCCESS !=
269 				csc->cp_stats_pdev_obj_init(pdev_cs)) {
270 			cp_stats_err("Failed to initialize pdev handlers");
271 			goto wlan_cp_stats_pdev_obj_create_handler_return;
272 		}
273 	}
274 
275 	status = wlan_objmgr_pdev_component_obj_attach(pdev,
276 						       WLAN_UMAC_COMP_CP_STATS,
277 						       pdev_cs,
278 						       QDF_STATUS_SUCCESS);
279 
280 	wlan_cp_stats_enable_init_cstats(pdev);
281 	cp_stats_debug("pdev cp stats object attached");
282 wlan_cp_stats_pdev_obj_create_handler_return:
283 	if (QDF_IS_STATUS_ERROR(status)) {
284 		if (csc) {
285 			if (csc->cp_stats_pdev_obj_deinit)
286 				csc->cp_stats_pdev_obj_deinit(pdev_cs);
287 		}
288 
289 		if (pdev_cs)
290 			qdf_mem_free(pdev_cs);
291 	}
292 
293 	return status;
294 }
295 
296 QDF_STATUS
297 wlan_cp_stats_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg)
298 {
299 	struct pdev_cp_stats *pdev_cs;
300 	struct cp_stats_context *csc;
301 
302 	if (!pdev) {
303 		cp_stats_err("pdev is NULL");
304 		return QDF_STATUS_E_INVAL;
305 	}
306 
307 	pdev_cs = wlan_objmgr_pdev_get_comp_private_obj(pdev,
308 						WLAN_UMAC_COMP_CP_STATS);
309 	if (!pdev_cs) {
310 		cp_stats_err("pdev is NULL");
311 		return QDF_STATUS_E_INVAL;
312 	}
313 	csc = wlan_cp_stats_ctx_get_from_pdev(pdev);
314 	if (!csc) {
315 		cp_stats_err("cp_stats context is NULL!");
316 		return QDF_STATUS_E_INVAL;
317 	}
318 
319 	if (csc->cp_stats_pdev_obj_deinit)
320 		csc->cp_stats_pdev_obj_deinit(pdev_cs);
321 
322 	wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CP_STATS,
323 					      pdev_cs);
324 
325 	qdf_mem_free(pdev_cs);
326 	cp_stats_debug("pdev cp stats object detached");
327 	return QDF_STATUS_SUCCESS;
328 }
329 
330 QDF_STATUS
331 wlan_cp_stats_vdev_obj_create_handler(struct wlan_objmgr_vdev *vdev, void *arg)
332 {
333 	struct cp_stats_context *csc = NULL;
334 	struct vdev_cp_stats *vdev_cs = NULL;
335 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
336 
337 	if (!vdev) {
338 		cp_stats_err("vdev is NULL");
339 		status = QDF_STATUS_E_INVAL;
340 		goto wlan_cp_stats_vdev_obj_create_handler_return;
341 	}
342 
343 	vdev_cs = qdf_mem_malloc(sizeof(*vdev_cs));
344 	if (!vdev_cs) {
345 		status = QDF_STATUS_E_NOMEM;
346 		goto wlan_cp_stats_vdev_obj_create_handler_return;
347 	}
348 	csc = wlan_cp_stats_ctx_get_from_vdev(vdev);
349 	if (!csc) {
350 		cp_stats_err("cp_stats context is NULL!");
351 		status = QDF_STATUS_E_INVAL;
352 		goto wlan_cp_stats_vdev_obj_create_handler_return;
353 	}
354 	vdev_cs->vdev_obj = vdev;
355 	if (csc->cp_stats_vdev_obj_init) {
356 		if (QDF_STATUS_SUCCESS !=
357 				csc->cp_stats_vdev_obj_init(vdev_cs)) {
358 			cp_stats_err("Failed to initialize vdev handlers");
359 			goto wlan_cp_stats_vdev_obj_create_handler_return;
360 		}
361 	}
362 
363 	status = wlan_objmgr_vdev_component_obj_attach(vdev,
364 						       WLAN_UMAC_COMP_CP_STATS,
365 						       vdev_cs,
366 						       QDF_STATUS_SUCCESS);
367 
368 wlan_cp_stats_vdev_obj_create_handler_return:
369 	if (QDF_IS_STATUS_ERROR(status)) {
370 		if (csc) {
371 			if (csc->cp_stats_vdev_obj_deinit)
372 				csc->cp_stats_vdev_obj_deinit(vdev_cs);
373 		}
374 
375 		if (vdev_cs)
376 			qdf_mem_free(vdev_cs);
377 	}
378 
379 	cp_stats_debug("vdev cp stats object attach");
380 	return status;
381 }
382 
383 QDF_STATUS
384 wlan_cp_stats_vdev_obj_destroy_handler(struct wlan_objmgr_vdev *vdev, void *arg)
385 {
386 	struct vdev_cp_stats *vdev_cs;
387 	struct cp_stats_context *csc;
388 
389 	if (!vdev) {
390 		cp_stats_err("vdev is NULL");
391 		return QDF_STATUS_E_INVAL;
392 	}
393 
394 	vdev_cs = wlan_objmgr_vdev_get_comp_private_obj(vdev,
395 						WLAN_UMAC_COMP_CP_STATS);
396 	if (!vdev_cs) {
397 		cp_stats_err("vdev is NULL");
398 		return QDF_STATUS_E_INVAL;
399 	}
400 	csc = wlan_cp_stats_ctx_get_from_vdev(vdev);
401 	if (!csc) {
402 		cp_stats_err("cp_stats context is NULL!");
403 		return QDF_STATUS_E_INVAL;
404 	}
405 
406 	if (csc->cp_stats_vdev_obj_deinit)
407 		csc->cp_stats_vdev_obj_deinit(vdev_cs);
408 
409 	wlan_objmgr_vdev_component_obj_detach(vdev, WLAN_UMAC_COMP_CP_STATS,
410 					      vdev_cs);
411 
412 	qdf_mem_free(vdev_cs);
413 	cp_stats_debug("vdev cp stats object detach");
414 	return QDF_STATUS_SUCCESS;
415 }
416 
417 QDF_STATUS
418 wlan_cp_stats_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg)
419 {
420 	struct cp_stats_context *csc = NULL;
421 	struct peer_cp_stats *peer_cs = NULL;
422 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
423 
424 	if (!peer) {
425 		cp_stats_err("peer is NULL");
426 		status = QDF_STATUS_E_INVAL;
427 		goto wlan_cp_stats_peer_obj_create_handler_return;
428 	}
429 
430 	peer_cs = qdf_mem_malloc(sizeof(*peer_cs));
431 	if (!peer_cs) {
432 		status = QDF_STATUS_E_NOMEM;
433 		goto wlan_cp_stats_peer_obj_create_handler_return;
434 	}
435 	csc = wlan_cp_stats_ctx_get_from_peer(peer);
436 	if (!csc) {
437 		cp_stats_err("cp_stats context is NULL!");
438 		status = QDF_STATUS_E_INVAL;
439 		goto wlan_cp_stats_peer_obj_create_handler_return;
440 	}
441 	peer_cs->peer_obj = peer;
442 	if (csc->cp_stats_peer_obj_init) {
443 		if (QDF_STATUS_SUCCESS !=
444 				csc->cp_stats_peer_obj_init(peer_cs)) {
445 			cp_stats_err("Failed to initialize peer handlers");
446 			goto wlan_cp_stats_peer_obj_create_handler_return;
447 		}
448 	}
449 
450 	status = wlan_objmgr_peer_component_obj_attach(peer,
451 						       WLAN_UMAC_COMP_CP_STATS,
452 						       peer_cs,
453 						       QDF_STATUS_SUCCESS);
454 
455 wlan_cp_stats_peer_obj_create_handler_return:
456 	if (QDF_IS_STATUS_ERROR(status)) {
457 		if (csc) {
458 			if (csc->cp_stats_peer_obj_deinit)
459 				csc->cp_stats_peer_obj_deinit(peer_cs);
460 		}
461 
462 		if (peer_cs)
463 			qdf_mem_free(peer_cs);
464 	}
465 
466 	cp_stats_debug("peer cp stats object attach");
467 	return status;
468 }
469 
470 QDF_STATUS
471 wlan_cp_stats_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg)
472 {
473 	struct peer_cp_stats *peer_cs;
474 	struct cp_stats_context *csc;
475 
476 	if (!peer) {
477 		cp_stats_err("peer is NULL");
478 		return QDF_STATUS_E_INVAL;
479 	}
480 
481 	peer_cs = wlan_objmgr_peer_get_comp_private_obj(peer,
482 						WLAN_UMAC_COMP_CP_STATS);
483 	if (!peer_cs) {
484 		cp_stats_err("peer is NULL");
485 		return QDF_STATUS_E_INVAL;
486 	}
487 	csc = wlan_cp_stats_ctx_get_from_peer(peer);
488 	if (!csc) {
489 		cp_stats_err("cp_stats context is NULL!");
490 		return QDF_STATUS_E_INVAL;
491 	}
492 
493 	if (csc->cp_stats_peer_obj_deinit)
494 		csc->cp_stats_peer_obj_deinit(peer_cs);
495 
496 	wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CP_STATS,
497 					      peer_cs);
498 
499 	qdf_mem_free(peer_cs);
500 	cp_stats_debug("peer cp stats object detached");
501 	return QDF_STATUS_SUCCESS;
502 }
503 
504 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS
505 QDF_STATUS
506 wlan_cp_stats_infra_cp_register_resp_cb(struct wlan_objmgr_psoc *psoc,
507 					struct infra_cp_stats_cmd_info *req)
508 {
509 	struct psoc_cp_stats *psoc_cp_stats_priv;
510 
511 	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
512 	if (!psoc_cp_stats_priv) {
513 		cp_stats_err("psoc cp stats object is null");
514 		return QDF_STATUS_E_NULL_VALUE;
515 	}
516 
517 	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
518 	psoc_cp_stats_priv->get_infra_cp_stats = req->infra_cp_stats_resp_cb;
519 	psoc_cp_stats_priv->infra_cp_stats_req_context = req->request_cookie;
520 	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
521 
522 	return QDF_STATUS_SUCCESS;
523 }
524 
525 QDF_STATUS
526 wlan_cp_stats_infra_cp_deregister_resp_cb(struct wlan_objmgr_psoc *psoc)
527 {
528 	struct psoc_cp_stats *psoc_cp_stats_priv;
529 
530 	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
531 	if (!psoc_cp_stats_priv) {
532 		cp_stats_err("psoc cp stats object is null");
533 		return QDF_STATUS_E_NULL_VALUE;
534 	}
535 
536 	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
537 	if (psoc_cp_stats_priv->get_infra_cp_stats)
538 		psoc_cp_stats_priv->get_infra_cp_stats = NULL;
539 	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
540 
541 	return QDF_STATUS_SUCCESS;
542 }
543 
544 QDF_STATUS
545 wlan_cp_stats_infra_cp_get_context(struct wlan_objmgr_psoc *psoc,
546 				   get_infra_cp_stats_cb *resp_cb,
547 				   void **context)
548 {
549 	struct psoc_cp_stats *psoc_cp_stats_priv;
550 
551 	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
552 	if (!psoc_cp_stats_priv) {
553 		cp_stats_err("psoc cp stats object is null");
554 		return QDF_STATUS_E_NULL_VALUE;
555 	}
556 
557 	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
558 	if (psoc_cp_stats_priv->get_infra_cp_stats)
559 		*resp_cb = psoc_cp_stats_priv->get_infra_cp_stats;
560 	if (psoc_cp_stats_priv->infra_cp_stats_req_context)
561 		*context = psoc_cp_stats_priv->infra_cp_stats_req_context;
562 	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
563 
564 	return QDF_STATUS_SUCCESS;
565 }
566 
567 QDF_STATUS
568 wlan_cp_stats_send_infra_cp_req(struct wlan_objmgr_psoc *psoc,
569 				struct infra_cp_stats_cmd_info *req)
570 {
571 	struct wlan_lmac_if_cp_stats_tx_ops *tx_ops;
572 
573 	tx_ops = target_if_cp_stats_get_tx_ops(psoc);
574 	if (!tx_ops) {
575 		cp_stats_err("could not get tx_ops");
576 		return QDF_STATUS_E_NULL_VALUE;
577 	}
578 
579 	if (!tx_ops->send_req_infra_cp_stats) {
580 		cp_stats_err("could not get send_req_infra_twt_stats");
581 		return QDF_STATUS_E_NULL_VALUE;
582 	}
583 	return tx_ops->send_req_infra_cp_stats(psoc, req);
584 }
585 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */
586 
587 #ifdef WLAN_CONFIG_TELEMETRY_AGENT
588 QDF_STATUS
589 wlan_cp_stats_send_telemetry_cp_req(struct wlan_objmgr_pdev *pdev,
590 				    struct infra_cp_stats_cmd_info *req)
591 {
592 	struct wlan_lmac_if_cp_stats_tx_ops *tx_ops;
593 
594 	tx_ops = target_if_cp_stats_get_tx_ops(wlan_pdev_get_psoc(pdev));
595 	if (!tx_ops) {
596 		cp_stats_err("could not get tx_ops");
597 		return QDF_STATUS_E_NULL_VALUE;
598 	}
599 
600 	if (!tx_ops->send_req_telemetry_cp_stats) {
601 		cp_stats_err("could not get send_req_infra_twt_stats");
602 		return QDF_STATUS_E_NULL_VALUE;
603 	}
604 	return tx_ops->send_req_telemetry_cp_stats(pdev, req);
605 }
606 #endif
607 
608 #if defined(WLAN_SUPPORT_TWT) && defined (WLAN_TWT_CONV_SUPPORTED)
609 /**
610  * wlan_cp_stats_twt_get_peer_session_param() - Obtains twt session parameters
611  * of a peer if twt session is valid
612  * @peer_cp_stat_prv: pointer to peer specific stats
613  * @params: Pointer to copy twt session parameters
614  * @num_twt_session: Pointer holding total number of valid twt sessions
615  *
616  * Return: QDF_STATUS success if valid twt session parameters are obtained
617  * else other qdf error values
618  */
619 static QDF_STATUS
620 wlan_cp_stats_twt_get_peer_session_param(struct peer_cp_stats *peer_cp_stat_prv,
621 					 struct twt_session_stats_info *params,
622 					 int *num_twt_session)
623 {
624 	struct twt_session_stats_info *twt_params;
625 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
626 	uint32_t event_type;
627 	int i;
628 
629 	if (!peer_cp_stat_prv || !params)
630 		return qdf_status;
631 
632 	for (i = 0; i < WLAN_MAX_TWT_SESSIONS_PER_PEER; i++) {
633 		twt_params = &peer_cp_stat_prv->twt_param[i];
634 		event_type = peer_cp_stat_prv->twt_param[i].event_type;
635 
636 		/* Check twt session is established */
637 
638 		if (event_type == HOST_TWT_SESSION_SETUP ||
639 		    event_type == HOST_TWT_SESSION_UPDATE) {
640 			qdf_mem_copy(&params[*num_twt_session], twt_params,
641 				     sizeof(*twt_params));
642 			qdf_status = QDF_STATUS_SUCCESS;
643 			*num_twt_session += 1;
644 		}
645 	}
646 
647 	return qdf_status;
648 }
649 
650 /**
651  * wlan_cp_stats_twt_get_all_peer_session_params()- Retrieves twt session
652  * parameters of all peers with valid twt session
653  * @psoc_obj: psoc object
654  * @vdev_id: vdev_id
655  * @params: array of pointer to store peer twt session parameters
656  *
657  * Return: total number of valid twt sessions
658  */
659 static int
660 wlan_cp_stats_twt_get_all_peer_session_params(
661 					struct wlan_objmgr_psoc *psoc_obj,
662 					uint8_t vdev_id,
663 					struct twt_session_stats_info *params)
664 {
665 	qdf_list_t *peer_list;
666 	struct wlan_objmgr_peer *peer, *peer_next;
667 	struct wlan_objmgr_vdev *vdev;
668 	struct peer_cp_stats *cp_stats_peer_obj, *peer_cp_stat_prv;
669 	int num_twt_session = 0;
670 	enum QDF_OPMODE opmode;
671 	uint16_t sap_num_peer;
672 
673 	if (!psoc_obj) {
674 		cp_stats_err("psoc is NULL");
675 		return num_twt_session;
676 	}
677 
678 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc_obj, vdev_id,
679 						    WLAN_CP_STATS_ID);
680 	if (!vdev) {
681 		cp_stats_err("vdev is NULL, vdev_id: %d", vdev_id);
682 		return num_twt_session;
683 	}
684 
685 	sap_num_peer = wlan_vdev_get_peer_count(vdev);
686 	opmode = wlan_vdev_mlme_get_opmode(vdev);
687 
688 	peer_list = &vdev->vdev_objmgr.wlan_peer_list;
689 	if (!peer_list) {
690 		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
691 		cp_stats_err("Peer list for vdev obj is NULL");
692 		return num_twt_session;
693 	}
694 
695 	peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list,
696 						    WLAN_CP_STATS_ID);
697 	while (peer) {
698 		cp_stats_peer_obj = wlan_objmgr_peer_get_comp_private_obj(
699 						peer, WLAN_UMAC_COMP_CP_STATS);
700 
701 		peer_cp_stat_prv = wlan_cp_stats_get_peer_stats_obj(peer);
702 		if (peer_cp_stat_prv) {
703 			wlan_cp_stats_peer_obj_lock(peer_cp_stat_prv);
704 			wlan_cp_stats_twt_get_peer_session_param(
705 							peer_cp_stat_prv,
706 							params,
707 							&num_twt_session);
708 			wlan_cp_stats_peer_obj_unlock(peer_cp_stat_prv);
709 		}
710 
711 		if (opmode == QDF_STA_MODE &&
712 		    num_twt_session >= WLAN_MAX_TWT_SESSIONS_PER_PEER) {
713 			wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
714 			goto done;
715 		}
716 
717 		if (opmode == QDF_SAP_MODE &&
718 		    num_twt_session >= (sap_num_peer * WLAN_MAX_TWT_SESSIONS_PER_PEER)) {
719 			wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
720 			goto done;
721 		}
722 
723 		peer_next = wlan_peer_get_next_active_peer_of_vdev(
724 						vdev, peer_list, peer,
725 						WLAN_CP_STATS_ID);
726 		wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
727 		peer = peer_next;
728 	}
729 done:
730 	if (!num_twt_session)
731 		cp_stats_err("Unable to find a peer with twt session established");
732 
733 	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
734 	return num_twt_session;
735 }
736 
737 /**
738  * wlan_cp_stats_twt_get_peer_session_param_by_dlg_id() - Finds a Peer twt
739  * session with dialog id matching with input dialog id. If a match is found
740  * copies the twt session parameters
741  * @peer_cp_stats_priv: pointer to peer specific stats
742  * @input_dialog_id: input dialog id
743  * @dest_param: Pointer to copy twt session parameters when a peer with
744  * given dialog id is found
745  * @num_twt_session: Pointer holding total number of valid twt session
746  *
747  * Return: Success if stats are copied for a peer with given dialog,
748  * else failure
749  */
750 static QDF_STATUS
751 wlan_cp_stats_twt_get_peer_session_param_by_dlg_id(
752 				struct peer_cp_stats *peer_cp_stats_priv,
753 				uint32_t input_dialog_id,
754 				struct twt_session_stats_info *dest_param,
755 				int *num_twt_session)
756 {
757 	struct twt_session_stats_info *src_param;
758 	uint32_t event_type;
759 	int i = 0;
760 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
761 
762 	if (!peer_cp_stats_priv || !dest_param)
763 		return qdf_status;
764 
765 	for (i = 0; i < WLAN_MAX_TWT_SESSIONS_PER_PEER; i++) {
766 		event_type = peer_cp_stats_priv->twt_param[i].event_type;
767 		src_param = &peer_cp_stats_priv->twt_param[i];
768 		if (!event_type ||
769 		    (src_param->dialog_id != input_dialog_id &&
770 		    input_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID))
771 			continue;
772 
773 		if (event_type == HOST_TWT_SESSION_SETUP ||
774 		    event_type == HOST_TWT_SESSION_UPDATE) {
775 			qdf_mem_copy(&dest_param[*num_twt_session], src_param,
776 				     sizeof(*src_param));
777 			qdf_status = QDF_STATUS_SUCCESS;
778 			*num_twt_session += 1;
779 			if (*num_twt_session >= WLAN_MAX_TWT_SESSIONS_PER_PEER)
780 				break;
781 		}
782 	}
783 
784 	return qdf_status;
785 }
786 
787 /**
788  * wlan_cp_stats_twt_get_single_peer_session_params()- Extracts twt session
789  * parameters corresponding to a peer given by dialog_id
790  * @psoc_obj: psoc object
791  * @mac_addr: mac addr of peer
792  * @dialog_id: dialog id of peer for which twt session params to be retrieved
793  * @params: pointer to store peer twt session parameters
794  *
795  * Return: total number of valid twt session
796  */
797 static int
798 wlan_cp_stats_twt_get_single_peer_session_params(
799 					struct wlan_objmgr_psoc *psoc_obj,
800 					uint8_t *mac_addr, uint32_t dialog_id,
801 					struct twt_session_stats_info *params)
802 {
803 	struct wlan_objmgr_peer *peer;
804 	struct peer_cp_stats *peer_cp_stats_priv;
805 	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
806 	int num_twt_session = 0;
807 
808 	if (!psoc_obj || !params)
809 		return num_twt_session;
810 
811 	peer = wlan_objmgr_get_peer_by_mac(psoc_obj, mac_addr,
812 					   WLAN_CP_STATS_ID);
813 	if (!peer)
814 		return num_twt_session;
815 	peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
816 
817 	if (!peer_cp_stats_priv) {
818 		wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
819 		return num_twt_session;
820 	}
821 
822 	wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
823 
824 	qdf_status = wlan_cp_stats_twt_get_peer_session_param_by_dlg_id(
825 							peer_cp_stats_priv,
826 							dialog_id,
827 							params,
828 							&num_twt_session);
829 	if (QDF_IS_STATUS_ERROR(qdf_status)) {
830 		cp_stats_debug("No TWT session for " QDF_MAC_ADDR_FMT " dialog_id %d",
831 			QDF_MAC_ADDR_REF(mac_addr), dialog_id);
832 	}
833 
834 	wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
835 	wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
836 
837 	return num_twt_session;
838 }
839 
840 int
841 wlan_cp_stats_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc,
842 					  struct twt_session_stats_info *params)
843 {
844 	uint8_t *mac_addr;
845 	uint32_t dialog_id;
846 	uint8_t vdev_id;
847 	int num_twt_session = 0;
848 
849 	if (!psoc || !params)
850 		return num_twt_session;
851 
852 	mac_addr = params[0].peer_mac.bytes;
853 	dialog_id = params[0].dialog_id;
854 	vdev_id = params[0].vdev_id;
855 
856 	/*
857 	 * Currently for STA case, twt_get_params nl is sending only dialog_id
858 	 * and mac_addr is being filled by driver in STA peer case.
859 	 * For SAP case, twt_get_params nl is sending dialog_id and
860 	 * peer mac_addr. When twt_get_params add mac_addr and dialog_id of
861 	 * STA/SAP, we need handle unicast/multicast macaddr in
862 	 * wlan_cp_stats_twt_get_peer_session_params.
863 	 */
864 	if (!QDF_IS_ADDR_BROADCAST(mac_addr))
865 		num_twt_session =
866 			wlan_cp_stats_twt_get_single_peer_session_params(
867 								psoc, mac_addr,
868 								dialog_id,
869 								params);
870 	else
871 		num_twt_session = wlan_cp_stats_twt_get_all_peer_session_params(
872 								psoc, vdev_id,
873 								params);
874 	return num_twt_session;
875 }
876 #endif /* WLAN_SUPPORT_TWT */
877