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