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