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
wlan_cp_stats_cstats_qmi_event_handler(void * cb_ctx,uint16_t type,void * event,int event_len)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
wlan_cp_stats_cstats_register_qmi_event_handler(struct cp_stats_context * csc)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  
wlan_cp_stats_init_cfg(struct wlan_objmgr_psoc * psoc,struct cp_stats_context * csc)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  
wlan_cp_stats_get_chipset_stats_enable(struct wlan_objmgr_psoc * psoc)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  
wlan_cp_stats_enable_init_cstats(struct wlan_objmgr_pdev * pdev)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
wlan_cp_stats_enable_init_cstats(struct wlan_objmgr_pdev * pdev)142  void wlan_cp_stats_enable_init_cstats(struct wlan_objmgr_pdev *pdev)
143  {
144  }
145  #endif /* WLAN_CHIPSET_STATS */
146  
147  QDF_STATUS
wlan_cp_stats_psoc_obj_create_handler(struct wlan_objmgr_psoc * psoc,void * arg)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
wlan_cp_stats_psoc_obj_destroy_handler(struct wlan_objmgr_psoc * psoc,void * arg)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
wlan_cp_stats_pdev_obj_create_handler(struct wlan_objmgr_pdev * pdev,void * arg)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
wlan_cp_stats_pdev_obj_destroy_handler(struct wlan_objmgr_pdev * pdev,void * arg)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
wlan_cp_stats_vdev_obj_create_handler(struct wlan_objmgr_vdev * vdev,void * arg)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
wlan_cp_stats_vdev_obj_destroy_handler(struct wlan_objmgr_vdev * vdev,void * arg)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
wlan_cp_stats_peer_obj_create_handler(struct wlan_objmgr_peer * peer,void * arg)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
wlan_cp_stats_peer_obj_destroy_handler(struct wlan_objmgr_peer * peer,void * arg)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
wlan_cp_stats_infra_cp_register_resp_cb(struct wlan_objmgr_psoc * psoc,struct infra_cp_stats_cmd_info * req)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
wlan_cp_stats_infra_cp_deregister_resp_cb(struct wlan_objmgr_psoc * psoc)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
wlan_cp_stats_infra_cp_get_context(struct wlan_objmgr_psoc * psoc,get_infra_cp_stats_cb * resp_cb,void ** context)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
wlan_cp_stats_send_infra_cp_req(struct wlan_objmgr_psoc * psoc,struct infra_cp_stats_cmd_info * req)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
wlan_cp_stats_send_telemetry_cp_req(struct wlan_objmgr_pdev * pdev,struct infra_cp_stats_cmd_info * req)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
wlan_cp_stats_twt_get_peer_session_param(struct peer_cp_stats * peer_cp_stat_prv,struct twt_session_stats_info * params,int * num_twt_session)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
wlan_cp_stats_twt_get_all_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,uint8_t vdev_id,struct twt_session_stats_info * params)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
wlan_cp_stats_twt_get_peer_session_param_by_dlg_id(struct peer_cp_stats * peer_cp_stats_priv,uint32_t input_dialog_id,struct twt_session_stats_info * dest_param,int * num_twt_session)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
wlan_cp_stats_twt_get_single_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,uint8_t * mac_addr,uint32_t dialog_id,struct twt_session_stats_info * params)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
wlan_cp_stats_twt_get_peer_session_params(struct wlan_objmgr_psoc * psoc,struct twt_session_stats_info * params)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