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_mc_ucfg_api.c
22   *
23   * This file provide API definitions required for northbound interaction
24   */
25  
26  #include <wlan_objmgr_psoc_obj.h>
27  #include "wlan_cp_stats_mc_defs.h"
28  #include <wlan_cp_stats_mc_ucfg_api.h>
29  #include <wlan_cp_stats_mc_tgt_api.h>
30  #include <wlan_cp_stats_utils_api.h>
31  #include "../../core/src/wlan_cp_stats_defs.h"
32  #include "../../core/src/wlan_cp_stats_cmn_api_i.h"
33  #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
34  #include <wlan_pmo_obj_mgmt_api.h>
35  #endif
36  #ifdef WLAN_SUPPORT_TWT
37  #include <wlan_mlme_twt_public_struct.h>
38  #endif
39  #include <wlan_mlme_api.h>
40  
41  #ifdef WLAN_SUPPORT_TWT
42  
43  /**
44   * ucfg_twt_get_peer_session_param_by_dlg_id() - Finds a Peer twt session with
45   * dialog id matching with input dialog id. If a match is found copies
46   * the twt session parameters
47   * @mc_stats: pointer to peer specific stats
48   * @input_dialog_id: input dialog id
49   * @dest_param: Pointer to copy twt session parameters when a peer with
50   * given dialog id is found
51   * @num_twt_session: Pointer holding total number of valid twt session
52   *
53   * Return: Success if stats are copied for a peer with given dialog,
54   * else failure
55   */
56  static QDF_STATUS
ucfg_twt_get_peer_session_param_by_dlg_id(struct peer_mc_cp_stats * mc_stats,uint32_t input_dialog_id,struct wmi_host_twt_session_stats_info * dest_param,int * num_twt_session)57  ucfg_twt_get_peer_session_param_by_dlg_id(struct peer_mc_cp_stats *mc_stats,
58  					  uint32_t input_dialog_id,
59  					  struct wmi_host_twt_session_stats_info
60  					  *dest_param, int *num_twt_session)
61  {
62  	struct wmi_host_twt_session_stats_info *src_param;
63  	uint32_t event_type;
64  	int i = 0;
65  	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
66  
67  	if (!mc_stats || !dest_param)
68  		return qdf_status;
69  
70  	for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) {
71  		event_type = mc_stats->twt_param[i].event_type;
72  
73  		src_param = &mc_stats->twt_param[i];
74  		if (!event_type ||
75  		    (src_param->dialog_id != input_dialog_id &&
76  		     input_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID))
77  			continue;
78  
79  		if ((event_type == HOST_TWT_SESSION_SETUP) ||
80  		    (event_type == HOST_TWT_SESSION_UPDATE)) {
81  			qdf_mem_copy(&dest_param[*num_twt_session], src_param,
82  				     sizeof(*src_param));
83  			qdf_status = QDF_STATUS_SUCCESS;
84  			*num_twt_session += 1;
85  			if (*num_twt_session >= TWT_PEER_MAX_SESSIONS)
86  				break;
87  		}
88  	}
89  
90  	return qdf_status;
91  }
92  
93  /**
94   * ucfg_twt_get_single_peer_session_params()- Extracts twt session parameters
95   * corresponding to a peer given by dialog_id
96   * @psoc_obj: psoc object
97   * @mac_addr: mac addr of peer
98   * @dialog_id: dialog id of peer for which twt session params to be retrieved
99   * @params: pointer to store peer twt session parameters
100   *
101   * Return: total number of valid twt session
102   */
103  static int
ucfg_twt_get_single_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,uint8_t * mac_addr,uint32_t dialog_id,struct wmi_host_twt_session_stats_info * params)104  ucfg_twt_get_single_peer_session_params(struct wlan_objmgr_psoc *psoc_obj,
105  					uint8_t *mac_addr, uint32_t dialog_id,
106  					struct wmi_host_twt_session_stats_info
107  					*params)
108  {
109  	struct wlan_objmgr_peer *peer;
110  	struct peer_cp_stats *peer_cp_stats_priv;
111  	struct peer_mc_cp_stats *peer_mc_stats;
112  	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
113  	int num_twt_session = 0;
114  
115  	if (!psoc_obj || !params)
116  		return num_twt_session;
117  
118  	peer = wlan_objmgr_get_peer_by_mac(psoc_obj, mac_addr,
119  					   WLAN_CP_STATS_ID);
120  	if (!peer)
121  		return num_twt_session;
122  
123  	peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
124  	if (!peer_cp_stats_priv) {
125  		wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
126  		return num_twt_session;
127  	}
128  
129  	wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
130  	peer_mc_stats = peer_cp_stats_priv->peer_stats;
131  
132  	qdf_status = ucfg_twt_get_peer_session_param_by_dlg_id(
133  							peer_mc_stats,
134  							dialog_id,
135  							params,
136  							&num_twt_session);
137  	if (QDF_IS_STATUS_ERROR(qdf_status)) {
138  		qdf_err("No TWT session for " QDF_MAC_ADDR_FMT " dialog_id %d",
139  			QDF_MAC_ADDR_REF(mac_addr), dialog_id);
140  	}
141  
142  	wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
143  	wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
144  
145  	return num_twt_session;
146  }
147  
148  /**
149   * ucfg_twt_get_peer_session_param() - Obtains twt session parameters of
150   * a peer if twt session is valid
151   * @mc_cp_stats: pointer to peer specific stats
152   * @params: Pointer to copy twt session parameters
153   * @num_twt_session: Pointer holding total number of valid twt sessions
154   *
155   * Return: QDF_STATUS success if valid twt session parameters are obtained
156   * else other qdf error values
157   */
158  static QDF_STATUS
ucfg_twt_get_peer_session_param(struct peer_mc_cp_stats * mc_cp_stats,struct wmi_host_twt_session_stats_info * params,int * num_twt_session)159  ucfg_twt_get_peer_session_param(struct peer_mc_cp_stats *mc_cp_stats,
160  				struct wmi_host_twt_session_stats_info *params,
161  				int *num_twt_session)
162  {
163  	struct wmi_host_twt_session_stats_info *twt_params;
164  	QDF_STATUS qdf_status = QDF_STATUS_E_INVAL;
165  	uint32_t event_type;
166  	int i;
167  
168  	if (!mc_cp_stats || !params)
169  		return qdf_status;
170  
171  	for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) {
172  		twt_params = &mc_cp_stats->twt_param[i];
173  		event_type = mc_cp_stats->twt_param[i].event_type;
174  
175  		/* Check twt session is established */
176  		if ((event_type == HOST_TWT_SESSION_SETUP) ||
177  		    (event_type == HOST_TWT_SESSION_UPDATE)) {
178  			qdf_mem_copy(&params[*num_twt_session], twt_params,
179  				     sizeof(*twt_params));
180  			qdf_status = QDF_STATUS_SUCCESS;
181  			*num_twt_session += 1;
182  		}
183  	}
184  	return qdf_status;
185  }
186  
187  /**
188   * ucfg_twt_get_all_peer_session_params()- Retrieves twt session parameters
189   * of all peers with valid twt session
190   * @psoc_obj: psoc object
191   * @vdev_id: vdev_id
192   * @params: array of pointer to store peer twt session parameters
193   *
194   * Return: total number of valid twt sessions
195   */
196  static int
ucfg_twt_get_all_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,uint8_t vdev_id,struct wmi_host_twt_session_stats_info * params)197  ucfg_twt_get_all_peer_session_params(struct wlan_objmgr_psoc *psoc_obj,
198  				     uint8_t vdev_id,
199  				     struct wmi_host_twt_session_stats_info
200  				     *params)
201  {
202  	qdf_list_t *peer_list;
203  	struct wlan_objmgr_peer *peer, *peer_next;
204  	struct wlan_objmgr_vdev *vdev;
205  	struct peer_cp_stats *cp_stats_peer_obj, *peer_cp_stat_prv;
206  	struct peer_mc_cp_stats *mc_cp_stats;
207  	int num_twt_session = 0;
208  	enum QDF_OPMODE opmode;
209  	int sap_max_peer = 0;
210  
211  	if (!psoc_obj) {
212  		cp_stats_err("psoc is NULL");
213  		return num_twt_session;
214  	}
215  
216  	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc_obj, vdev_id,
217  						    WLAN_CP_STATS_ID);
218  
219  	if (!vdev) {
220  		cp_stats_err("vdev is NULL, vdev_id: %d", vdev_id);
221  		return num_twt_session;
222  	}
223  
224  	wlan_mlme_get_sap_max_peers(psoc_obj, &sap_max_peer);
225  	opmode = wlan_vdev_mlme_get_opmode(vdev);
226  
227  	peer_list = &vdev->vdev_objmgr.wlan_peer_list;
228  	if (!peer_list) {
229  		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
230  		cp_stats_err("Peer list for vdev obj is NULL");
231  		return num_twt_session;
232  	}
233  
234  	peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list,
235  						    WLAN_CP_STATS_ID);
236  
237  	while (peer) {
238  		cp_stats_peer_obj = wlan_objmgr_peer_get_comp_private_obj(
239  						peer, WLAN_UMAC_COMP_CP_STATS);
240  
241  		mc_cp_stats = NULL;
242  		if (cp_stats_peer_obj)
243  			mc_cp_stats = cp_stats_peer_obj->peer_stats;
244  
245  		peer_cp_stat_prv =
246  			wlan_cp_stats_get_peer_stats_obj(peer);
247  
248  		if (peer_cp_stat_prv && mc_cp_stats) {
249  			wlan_cp_stats_peer_obj_lock(peer_cp_stat_prv);
250  			ucfg_twt_get_peer_session_param(mc_cp_stats,
251  							params,
252  							&num_twt_session);
253  			wlan_cp_stats_peer_obj_unlock(peer_cp_stat_prv);
254  		}
255  
256  		if (opmode == QDF_STA_MODE &&
257  		    num_twt_session >= TWT_PEER_MAX_SESSIONS) {
258  			wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
259  			goto done;
260  		}
261  
262  		if (opmode == QDF_SAP_MODE &&
263  		    num_twt_session >= (sap_max_peer * TWT_PEER_MAX_SESSIONS)) {
264  			wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
265  			goto done;
266  		}
267  
268  		peer_next = wlan_peer_get_next_active_peer_of_vdev(
269  							vdev, peer_list, peer,
270  							WLAN_CP_STATS_ID);
271  		wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
272  		peer = peer_next;
273  	}
274  
275  done:
276  	if (!num_twt_session)
277  		cp_stats_err("Unable to find a peer with twt session established");
278  
279  	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
280  	return num_twt_session;
281  }
282  
283  int
ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc * psoc_obj,struct wmi_host_twt_session_stats_info * params)284  ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc_obj,
285  				 struct wmi_host_twt_session_stats_info *params)
286  {
287  	uint8_t *mac_addr;
288  	uint32_t dialog_id;
289  	uint8_t vdev_id;
290  	int num_twt_session = 0;
291  
292  	if (!psoc_obj || !params)
293  		return num_twt_session;
294  
295  	mac_addr = params[0].peer_mac;
296  	dialog_id = params[0].dialog_id;
297  	vdev_id = params[0].vdev_id;
298  
299  	/*
300  	 * Currently for STA case, twt_get_params nl is sending only dialog_id
301  	 * and mac_addr is being filled by driver in STA peer case.
302  	 * For SAP case, twt_get_params nl is sending dialog_id and
303  	 * peer mac_addr. When twt_get_params add mac_addr and dialog_id of
304  	 * STA/SAP, we need handle unicast/multicast macaddr in
305  	 * ucfg_twt_get_peer_session_params.
306  	 */
307  	if (!QDF_IS_ADDR_BROADCAST(mac_addr))
308  		num_twt_session = ucfg_twt_get_single_peer_session_params(
309  								psoc_obj,
310  								mac_addr,
311  								dialog_id,
312  								params);
313  	else
314  		num_twt_session = ucfg_twt_get_all_peer_session_params(
315  								psoc_obj,
316  								vdev_id,
317  								params);
318  
319  	return num_twt_session;
320  }
321  #endif /* WLAN_SUPPORT_TWT */
322  
wlan_cp_stats_psoc_cs_init(struct psoc_cp_stats * psoc_cs)323  QDF_STATUS wlan_cp_stats_psoc_cs_init(struct psoc_cp_stats *psoc_cs)
324  {
325  	psoc_cs->obj_stats = qdf_mem_malloc(sizeof(struct psoc_mc_cp_stats));
326  	if (!psoc_cs->obj_stats)
327  		return QDF_STATUS_E_NOMEM;
328  
329  	return QDF_STATUS_SUCCESS;
330  }
331  
wlan_cp_stats_psoc_cs_deinit(struct psoc_cp_stats * psoc_cs)332  QDF_STATUS wlan_cp_stats_psoc_cs_deinit(struct psoc_cp_stats *psoc_cs)
333  {
334  	qdf_mem_free(psoc_cs->obj_stats);
335  	psoc_cs->obj_stats = NULL;
336  	return QDF_STATUS_SUCCESS;
337  }
338  
wlan_cp_stats_vdev_cs_init(struct vdev_cp_stats * vdev_cs)339  QDF_STATUS wlan_cp_stats_vdev_cs_init(struct vdev_cp_stats *vdev_cs)
340  {
341  	vdev_cs->vdev_stats = qdf_mem_malloc(sizeof(struct vdev_mc_cp_stats));
342  	if (!vdev_cs->vdev_stats)
343  		return QDF_STATUS_E_NOMEM;
344  
345  	return QDF_STATUS_SUCCESS;
346  }
347  
wlan_cp_stats_vdev_cs_deinit(struct vdev_cp_stats * vdev_cs)348  QDF_STATUS wlan_cp_stats_vdev_cs_deinit(struct vdev_cp_stats *vdev_cs)
349  {
350  	qdf_mem_free(vdev_cs->vdev_stats);
351  	vdev_cs->vdev_stats = NULL;
352  	return QDF_STATUS_SUCCESS;
353  }
354  
wlan_cp_stats_pdev_cs_init(struct pdev_cp_stats * pdev_cs)355  QDF_STATUS wlan_cp_stats_pdev_cs_init(struct pdev_cp_stats *pdev_cs)
356  {
357  	pdev_cs->pdev_stats = qdf_mem_malloc(sizeof(struct pdev_mc_cp_stats));
358  	if (!pdev_cs->pdev_stats)
359  		return QDF_STATUS_E_NOMEM;
360  
361  	return QDF_STATUS_SUCCESS;
362  }
363  
wlan_cp_stats_pdev_cs_deinit(struct pdev_cp_stats * pdev_cs)364  QDF_STATUS wlan_cp_stats_pdev_cs_deinit(struct pdev_cp_stats *pdev_cs)
365  {
366  	qdf_mem_free(pdev_cs->pdev_stats);
367  	pdev_cs->pdev_stats = NULL;
368  	return QDF_STATUS_SUCCESS;
369  }
370  
wlan_cp_stats_peer_cs_init(struct peer_cp_stats * peer_cs)371  QDF_STATUS wlan_cp_stats_peer_cs_init(struct peer_cp_stats *peer_cs)
372  {
373  	struct peer_mc_cp_stats *peer_mc_stats;
374  
375  	peer_mc_stats = qdf_mem_malloc(sizeof(struct peer_mc_cp_stats));
376  	if (!peer_mc_stats)
377  		return QDF_STATUS_E_NOMEM;
378  
379  	peer_mc_stats->adv_stats =
380  			qdf_mem_malloc(sizeof(struct peer_adv_mc_cp_stats));
381  
382  	if (!peer_mc_stats->adv_stats) {
383  		qdf_mem_free(peer_mc_stats);
384  		peer_mc_stats = NULL;
385  		return QDF_STATUS_E_NOMEM;
386  	}
387  
388  	peer_mc_stats->extd_stats =
389  			qdf_mem_malloc(sizeof(struct peer_extd_stats));
390  
391  	if (!peer_mc_stats->extd_stats) {
392  		qdf_mem_free(peer_mc_stats->adv_stats);
393  		peer_mc_stats->adv_stats = NULL;
394  		qdf_mem_free(peer_mc_stats);
395  		peer_mc_stats = NULL;
396  		return QDF_STATUS_E_NOMEM;
397  	}
398  	peer_cs->peer_stats = peer_mc_stats;
399  
400  	return QDF_STATUS_SUCCESS;
401  }
402  
wlan_cp_stats_peer_cs_deinit(struct peer_cp_stats * peer_cs)403  QDF_STATUS wlan_cp_stats_peer_cs_deinit(struct peer_cp_stats *peer_cs)
404  {
405  	struct peer_mc_cp_stats *peer_mc_stats = peer_cs->peer_stats;
406  
407  	qdf_mem_free(peer_mc_stats->adv_stats);
408  	peer_mc_stats->adv_stats = NULL;
409  	qdf_mem_free(peer_mc_stats->extd_stats);
410  	peer_mc_stats->extd_stats = NULL;
411  	qdf_mem_free(peer_cs->peer_stats);
412  	peer_cs->peer_stats = NULL;
413  
414  	return QDF_STATUS_SUCCESS;
415  }
416  
ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,enum qdf_proto_subtype protocol)417  QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol(
418  					struct wlan_objmgr_psoc *psoc,
419  					uint8_t vdev_id,
420  					enum qdf_proto_subtype protocol)
421  {
422  	struct wake_lock_stats *stats;
423  	struct psoc_cp_stats *psoc_cp_stats_priv;
424  	struct psoc_mc_cp_stats *psoc_mc_stats;
425  
426  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
427  	if (!psoc_cp_stats_priv) {
428  		cp_stats_err("psoc cp stats object is null");
429  		return QDF_STATUS_E_NULL_VALUE;
430  	}
431  
432  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
433  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
434  
435  	if (!psoc_mc_stats) {
436  		cp_stats_err("psoc mc stats is null");
437  		return QDF_STATUS_E_NULL_VALUE;
438  	}
439  
440  	stats = &psoc_mc_stats->wow_stats;
441  	switch (protocol) {
442  	case QDF_PROTO_ICMP_REQ:
443  	case QDF_PROTO_ICMP_RES:
444  		stats->icmpv4_count++;
445  		break;
446  	case QDF_PROTO_ICMPV6_REQ:
447  	case QDF_PROTO_ICMPV6_RES:
448  	case QDF_PROTO_ICMPV6_RS:
449  		stats->icmpv6_count++;
450  		break;
451  	case QDF_PROTO_ICMPV6_RA:
452  		stats->icmpv6_count++;
453  		stats->ipv6_mcast_ra_stats++;
454  		break;
455  	case QDF_PROTO_ICMPV6_NS:
456  		stats->icmpv6_count++;
457  		stats->ipv6_mcast_ns_stats++;
458  		break;
459  	case QDF_PROTO_ICMPV6_NA:
460  		stats->icmpv6_count++;
461  		stats->ipv6_mcast_na_stats++;
462  		break;
463  	default:
464  		break;
465  	}
466  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
467  
468  	return QDF_STATUS_SUCCESS;
469  }
470  
ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint8_t * dest_mac)471  QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr(
472  					struct wlan_objmgr_psoc *psoc,
473  					uint8_t vdev_id, uint8_t *dest_mac)
474  {
475  	struct psoc_cp_stats *psoc_cp_stats_priv;
476  	struct psoc_mc_cp_stats *psoc_mc_stats;
477  	struct wake_lock_stats *stats;
478  
479  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
480  	if (!psoc_cp_stats_priv) {
481  		cp_stats_err("psoc cp stats object is null");
482  		return QDF_STATUS_E_NULL_VALUE;
483  	}
484  
485  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
486  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
487  	if (!psoc_mc_stats) {
488  		cp_stats_err("psoc mc stats is null");
489  		return QDF_STATUS_E_NULL_VALUE;
490  	}
491  
492  	stats = &psoc_mc_stats->wow_stats;
493  
494  	switch (*dest_mac) {
495  	case QDF_BCAST_MAC_ADDR:
496  		stats->bcast_wake_up_count++;
497  		break;
498  	case QDF_MCAST_IPV4_MAC_ADDR:
499  		stats->ipv4_mcast_wake_up_count++;
500  		break;
501  	case QDF_MCAST_IPV6_MAC_ADDR:
502  		stats->ipv6_mcast_wake_up_count++;
503  		break;
504  	default:
505  		stats->ucast_wake_up_count++;
506  		break;
507  	}
508  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
509  
510  	return QDF_STATUS_SUCCESS;
511  }
512  
ucfg_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,uint32_t reason)513  QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc *psoc,
514  						uint8_t vdev_id,
515  						uint32_t reason)
516  {
517  	struct wake_lock_stats *stats;
518  	QDF_STATUS status = QDF_STATUS_SUCCESS;
519  	struct psoc_mc_cp_stats *psoc_mc_stats;
520  	struct psoc_cp_stats *psoc_cp_stats_priv;
521  
522  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
523  	if (!psoc_cp_stats_priv) {
524  		cp_stats_err("psoc cp stats object is null");
525  		return QDF_STATUS_E_NULL_VALUE;
526  	}
527  
528  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
529  
530  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
531  
532  	if (!psoc_mc_stats) {
533  		cp_stats_err("psoc mc stats is null");
534  		wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
535  		return QDF_STATUS_E_NULL_VALUE;
536  	}
537  
538  	stats = &psoc_mc_stats->wow_stats;
539  
540  	status = tgt_mc_cp_stats_inc_wake_lock_stats(psoc, reason, stats,
541  				&psoc_mc_stats->wow_unspecified_wake_up_count);
542  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
543  
544  	return status;
545  }
546  
547  /**
548   * vdev_iterator() - iterator function to collect wake_lock_stats from all vdev
549   * @psoc: pointer to psoc object
550   * @vdev: pointer to vdev object
551   * @arg: stats object pointer passed as arg
552   *
553   * Return - none
554   */
vdev_iterator(struct wlan_objmgr_psoc * psoc,void * vdev,void * arg)555  static void vdev_iterator(struct wlan_objmgr_psoc *psoc, void *vdev, void *arg)
556  {
557  	struct wake_lock_stats *vdev_stats;
558  	struct wake_lock_stats *stats = arg;
559  	struct psoc_cp_stats *psoc_cp_stats_priv;
560  	struct psoc_mc_cp_stats *psoc_mc_stats;
561  
562  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
563  	if (!psoc_cp_stats_priv) {
564  		cp_stats_err("psoc cp stats object is null");
565  		return;
566  	}
567  
568  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
569  	if (!psoc_mc_stats) {
570  		cp_stats_err("psoc mc stats is null");
571  		return;
572  	}
573  
574  	vdev_stats = &psoc_mc_stats->wow_stats;
575  
576  	stats->ucast_wake_up_count += vdev_stats->ucast_wake_up_count;
577  	stats->bcast_wake_up_count += vdev_stats->bcast_wake_up_count;
578  	stats->ipv4_mcast_wake_up_count += vdev_stats->ipv4_mcast_wake_up_count;
579  	stats->ipv6_mcast_wake_up_count += vdev_stats->ipv6_mcast_wake_up_count;
580  	stats->ipv6_mcast_ra_stats += vdev_stats->ipv6_mcast_ra_stats;
581  	stats->ipv6_mcast_ns_stats += vdev_stats->ipv6_mcast_ns_stats;
582  	stats->ipv6_mcast_na_stats += vdev_stats->ipv6_mcast_na_stats;
583  	stats->icmpv4_count += vdev_stats->icmpv4_count;
584  	stats->icmpv6_count += vdev_stats->icmpv6_count;
585  	stats->rssi_breach_wake_up_count +=
586  			vdev_stats->rssi_breach_wake_up_count;
587  	stats->low_rssi_wake_up_count += vdev_stats->low_rssi_wake_up_count;
588  	stats->gscan_wake_up_count += vdev_stats->gscan_wake_up_count;
589  	stats->pno_complete_wake_up_count +=
590  			vdev_stats->pno_complete_wake_up_count;
591  	stats->pno_match_wake_up_count += vdev_stats->pno_match_wake_up_count;
592  	stats->oem_response_wake_up_count +=
593  			vdev_stats->oem_response_wake_up_count;
594  	stats->uc_drop_wake_up_count += vdev_stats->uc_drop_wake_up_count;
595  	stats->fatal_event_wake_up_count +=
596  			vdev_stats->fatal_event_wake_up_count;
597  	stats->pwr_save_fail_detected += vdev_stats->pwr_save_fail_detected;
598  	stats->scan_11d += vdev_stats->scan_11d;
599  }
600  
ucfg_mc_cp_stats_get_psoc_wake_lock_stats(struct wlan_objmgr_psoc * psoc,struct wake_lock_stats * stats)601  QDF_STATUS ucfg_mc_cp_stats_get_psoc_wake_lock_stats(
602  						struct wlan_objmgr_psoc *psoc,
603  						struct wake_lock_stats *stats)
604  {
605  	struct psoc_cp_stats *psoc_cp_stats_priv;
606  	struct psoc_mc_cp_stats *psoc_mc_stats;
607  
608  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
609  	if (!psoc_cp_stats_priv) {
610  		cp_stats_err("psoc cp stats object is null");
611  		return QDF_STATUS_E_NULL_VALUE;
612  	}
613  
614  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
615  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
616  	/* iterate through all vdevs, and get wow stats from vdev_cs object */
617  	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, vdev_iterator,
618  				     stats, true, WLAN_CP_STATS_ID);
619  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
620  
621  	return QDF_STATUS_SUCCESS;
622  }
623  
ucfg_mc_cp_stats_get_vdev_wake_lock_stats(struct wlan_objmgr_vdev * vdev,struct wake_lock_stats * stats)624  QDF_STATUS ucfg_mc_cp_stats_get_vdev_wake_lock_stats(
625  						struct wlan_objmgr_vdev *vdev,
626  						struct wake_lock_stats *stats)
627  {
628  	struct wlan_objmgr_psoc *psoc;
629  	struct psoc_cp_stats *psoc_cp_stats_priv;
630  	struct psoc_mc_cp_stats *psoc_mc_stats;
631  
632  	wlan_vdev_obj_lock(vdev);
633  	psoc = wlan_vdev_get_psoc(vdev);
634  	if (!psoc) {
635  		wlan_vdev_obj_unlock(vdev);
636  		cp_stats_err("psoc NULL");
637  		return QDF_STATUS_E_INVAL;
638  	}
639  	wlan_vdev_obj_unlock(vdev);
640  
641  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
642  	if (!psoc_cp_stats_priv) {
643  		cp_stats_err("psoc cp stats object is null");
644  		return QDF_STATUS_E_NULL_VALUE;
645  	}
646  
647  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
648  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
649  
650  	if (!psoc_mc_stats) {
651  		cp_stats_err("psoc mc stats is null");
652  		return QDF_STATUS_E_NULL_VALUE;
653  	}
654  
655  	qdf_mem_copy(stats, &psoc_mc_stats->wow_stats, sizeof(*stats));
656  
657  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
658  
659  	return QDF_STATUS_SUCCESS;
660  }
661  
ucfg_mc_cp_stats_write_wow_stats(struct wlan_objmgr_psoc * psoc,char * buffer,uint16_t max_len,int * ret)662  QDF_STATUS ucfg_mc_cp_stats_write_wow_stats(
663  				struct wlan_objmgr_psoc *psoc,
664  				char *buffer, uint16_t max_len, int *ret)
665  {
666  	QDF_STATUS status;
667  	uint32_t unspecified_wake_count;
668  	struct wake_lock_stats wow_stats = {0};
669  	struct psoc_mc_cp_stats *psoc_mc_stats;
670  	struct psoc_cp_stats *psoc_cp_stats_priv;
671  
672  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
673  	if (!psoc_cp_stats_priv) {
674  		cp_stats_err("psoc cp stats object is null");
675  		return QDF_STATUS_E_NULL_VALUE;
676  	}
677  
678  	/* get stats from psoc */
679  	status = ucfg_mc_cp_stats_get_psoc_wake_lock_stats(psoc, &wow_stats);
680  	if (QDF_IS_STATUS_ERROR(status)) {
681  		cp_stats_err("Failed to get WoW stats");
682  		return status;
683  	}
684  
685  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
686  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
687  	unspecified_wake_count = psoc_mc_stats->wow_unspecified_wake_up_count;
688  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
689  
690  	*ret = qdf_scnprintf(buffer, max_len,
691  			     "WoW Wake Reasons\n"
692  			     "\tunspecified wake count: %u\n"
693  			     "\tunicast: %u\n"
694  			     "\tbroadcast: %u\n"
695  			     "\tIPv4 multicast: %u\n"
696  			     "\tIPv6 multicast: %u\n"
697  			     "\tIPv6 multicast RA: %u\n"
698  			     "\tIPv6 multicast NS: %u\n"
699  			     "\tIPv6 multicast NA: %u\n"
700  			     "\tICMPv4: %u\n"
701  			     "\tICMPv6: %u\n"
702  			     "\tRSSI Breach: %u\n"
703  			     "\tLow RSSI: %u\n"
704  			     "\tG-Scan: %u\n"
705  			     "\tPNO Complete: %u\n"
706  			     "\tPNO Match: %u\n"
707  			     "\tUC Drop wake_count: %u\n"
708  			     "\twake count due to fatal event: %u\n"
709  			     "\tOEM rsp wake_count: %u\n"
710  			     "\twake count due to pwr_save_fail_detected: %u\n"
711  			     "\twake count due to 11d scan: %u\n",
712  			     unspecified_wake_count,
713  			     wow_stats.ucast_wake_up_count,
714  			     wow_stats.bcast_wake_up_count,
715  			     wow_stats.ipv4_mcast_wake_up_count,
716  			     wow_stats.ipv6_mcast_wake_up_count,
717  			     wow_stats.ipv6_mcast_ra_stats,
718  			     wow_stats.ipv6_mcast_ns_stats,
719  			     wow_stats.ipv6_mcast_na_stats,
720  			     wow_stats.icmpv4_count,
721  			     wow_stats.icmpv6_count,
722  			     wow_stats.rssi_breach_wake_up_count,
723  			     wow_stats.low_rssi_wake_up_count,
724  			     wow_stats.gscan_wake_up_count,
725  			     wow_stats.pno_complete_wake_up_count,
726  			     wow_stats.pno_match_wake_up_count,
727  			     wow_stats.uc_drop_wake_up_count,
728  			     wow_stats.fatal_event_wake_up_count,
729  			     wow_stats.oem_response_wake_up_count,
730  			     wow_stats.pwr_save_fail_detected,
731  			     wow_stats.scan_11d);
732  
733  	return QDF_STATUS_SUCCESS;
734  }
735  
ucfg_mc_cp_stats_send_stats_request(struct wlan_objmgr_vdev * vdev,enum stats_req_type type,struct request_info * info)736  QDF_STATUS ucfg_mc_cp_stats_send_stats_request(struct wlan_objmgr_vdev *vdev,
737  					       enum stats_req_type type,
738  					       struct request_info *info)
739  {
740  	QDF_STATUS status;
741  
742  	status = ucfg_mc_cp_stats_set_pending_req(wlan_vdev_get_psoc(vdev),
743  						  type, info);
744  	if (QDF_IS_STATUS_ERROR(status)) {
745  		cp_stats_err("ucfg_mc_cp_stats_set_pending_req pdev failed: %d",
746  			     status);
747  		return status;
748  	}
749  
750  	return tgt_send_mc_cp_stats_req(wlan_vdev_get_psoc(vdev), type, info);
751  }
752  
753  #ifdef WLAN_FEATURE_BIG_DATA_STATS
ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev * vdev,enum stats_req_type type,struct request_info * info)754  QDF_STATUS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev *vdev,
755  					    enum stats_req_type type,
756  					    struct request_info *info)
757  {
758  	QDF_STATUS status;
759  
760  	status = ucfg_mc_cp_stats_set_pending_req(wlan_vdev_get_psoc(vdev),
761  						  type, info);
762  	if (QDF_IS_STATUS_ERROR(status)) {
763  		cp_stats_err("ucfg_mc_cp_stats_set_pending_req pdev failed: %d",
764  			     status);
765  		return status;
766  	}
767  	return tgt_send_mc_cp_stats_req(wlan_vdev_get_psoc(vdev), type, info);
768  }
769  
ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc * psoc,bool enable)770  void ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc *psoc,
771  					bool enable)
772  {
773  	struct psoc_mc_cp_stats *psoc_mc_stats;
774  	struct psoc_cp_stats *psoc_cp_stats_priv;
775  
776  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
777  	if (!psoc_cp_stats_priv) {
778  		cp_stats_err("psoc cp stats object is null");
779  		return;
780  	}
781  
782  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
783  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
784  	psoc_mc_stats->big_data_fw_support_enable = enable;
785  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
786  }
787  
ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc * psoc,bool * enable)788  void ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc *psoc,
789  					bool *enable)
790  {
791  	struct psoc_mc_cp_stats *psoc_mc_stats;
792  	struct psoc_cp_stats *psoc_cp_stats_priv;
793  
794  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
795  	if (!psoc_cp_stats_priv) {
796  		cp_stats_err("psoc cp stats object is null");
797  		return;
798  	}
799  
800  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
801  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
802  	*enable = psoc_mc_stats->big_data_fw_support_enable;
803  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
804  }
805  #endif
806  
ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev * vdev,int * dbm)807  QDF_STATUS ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev,
808  					 int *dbm)
809  {
810  	struct wlan_objmgr_pdev *pdev;
811  	struct pdev_mc_cp_stats *pdev_mc_stats;
812  	struct pdev_cp_stats *pdev_cp_stats_priv;
813  	struct vdev_mc_cp_stats *vdev_mc_stats;
814  	struct vdev_cp_stats *vdev_cp_stat;
815  	uint32_t vdev_power = 0;
816  
817  	vdev_cp_stat = wlan_cp_stats_get_vdev_stats_obj(vdev);
818  	if (vdev_cp_stat) {
819  		wlan_cp_stats_vdev_obj_lock(vdev_cp_stat);
820  		vdev_mc_stats = vdev_cp_stat->vdev_stats;
821  		vdev_power = vdev_mc_stats->vdev_extd_stats.vdev_tx_power;
822  		wlan_cp_stats_vdev_obj_unlock(vdev_cp_stat);
823  		if (vdev_power) {
824  			*dbm = vdev_power;
825  			return QDF_STATUS_SUCCESS;
826  		}
827  	}
828  
829  	pdev = wlan_vdev_get_pdev(vdev);
830  	pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
831  	if (!pdev_cp_stats_priv) {
832  		cp_stats_err("pdev cp stats object is null");
833  		return QDF_STATUS_E_NULL_VALUE;
834  	}
835  
836  	wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv);
837  	pdev_mc_stats = pdev_cp_stats_priv->pdev_stats;
838  	*dbm = pdev_mc_stats->max_pwr;
839  	wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv);
840  
841  	return QDF_STATUS_SUCCESS;
842  }
843  
ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc * psoc,enum stats_req_type type)844  bool ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc *psoc,
845  				     enum stats_req_type type)
846  {
847  	uint32_t pending_req_map;
848  	struct psoc_mc_cp_stats *psoc_mc_stats;
849  	struct psoc_cp_stats *psoc_cp_stats_priv;
850  
851  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
852  	if (!psoc_cp_stats_priv) {
853  		cp_stats_err("psoc cp stats object is null");
854  		return false;
855  	}
856  
857  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
858  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
859  	pending_req_map = psoc_mc_stats->pending.type_map;
860  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
861  
862  	return (pending_req_map & (1 << type));
863  }
864  
ucfg_mc_cp_stats_set_pending_req(struct wlan_objmgr_psoc * psoc,enum stats_req_type type,struct request_info * req)865  QDF_STATUS ucfg_mc_cp_stats_set_pending_req(struct wlan_objmgr_psoc *psoc,
866  					    enum stats_req_type type,
867  					    struct request_info *req)
868  {
869  	struct psoc_mc_cp_stats *psoc_mc_stats;
870  	struct psoc_cp_stats *psoc_cp_stats_priv;
871  
872  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
873  	if (!psoc_cp_stats_priv) {
874  		cp_stats_err("psoc cp stats object is null");
875  		return QDF_STATUS_E_NULL_VALUE;
876  	}
877  
878  	if (type >= TYPE_MAX) {
879  		cp_stats_err("Invalid type index: %d", type);
880  		return QDF_STATUS_E_INVAL;
881  	}
882  
883  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
884  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
885  	if (psoc_mc_stats->is_cp_stats_suspended) {
886  		cp_stats_debug("cp stats is suspended try again after resume");
887  		wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
888  		return QDF_STATUS_E_AGAIN;
889  	}
890  	psoc_mc_stats->pending.type_map |= (1 << type);
891  	psoc_mc_stats->pending.req[type] = *req;
892  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
893  
894  	return QDF_STATUS_SUCCESS;
895  }
896  
ucfg_mc_cp_stats_reset_pending_req(struct wlan_objmgr_psoc * psoc,enum stats_req_type type,struct request_info * last_req,bool * pending)897  QDF_STATUS ucfg_mc_cp_stats_reset_pending_req(struct wlan_objmgr_psoc *psoc,
898  					      enum stats_req_type type,
899  					      struct request_info *last_req,
900  					      bool *pending)
901  {
902  	struct psoc_mc_cp_stats *psoc_mc_stats;
903  	struct psoc_cp_stats *psoc_cp_stats_priv;
904  
905  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
906  	if (!psoc_cp_stats_priv) {
907  		cp_stats_err("psoc cp stats object is null");
908  		return QDF_STATUS_E_NULL_VALUE;
909  	}
910  
911  	if (type >= TYPE_MAX) {
912  		cp_stats_err("Invalid type index: %d", type);
913  		return QDF_STATUS_E_INVAL;
914  	}
915  
916  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
917  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
918  	if (psoc_mc_stats->pending.type_map & (1 << type)) {
919  		*last_req = psoc_mc_stats->pending.req[type];
920  		*pending = true;
921  	} else {
922  		*pending = false;
923  	}
924  	psoc_mc_stats->pending.type_map &= ~(1 << type);
925  	qdf_mem_zero(&psoc_mc_stats->pending.req[type],
926  		     sizeof(psoc_mc_stats->pending.req[type]));
927  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
928  
929  	return QDF_STATUS_SUCCESS;
930  }
931  
ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc * psoc,enum stats_req_type type,struct request_info * info)932  QDF_STATUS ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc *psoc,
933  					    enum stats_req_type type,
934  					    struct request_info *info)
935  {
936  	struct psoc_mc_cp_stats *psoc_mc_stats;
937  	struct psoc_cp_stats *psoc_cp_stats_priv;
938  
939  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
940  	if (!psoc_cp_stats_priv) {
941  		cp_stats_err("psoc cp stats object is null");
942  		return QDF_STATUS_E_NULL_VALUE;
943  	}
944  
945  	if (type >= TYPE_MAX) {
946  		cp_stats_err("Invalid type index: %d", type);
947  		return QDF_STATUS_E_INVAL;
948  	}
949  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
950  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
951  	*info = psoc_mc_stats->pending.req[type];
952  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
953  
954  	return QDF_STATUS_SUCCESS;
955  }
956  
957  /**
958   * ucfg_mc_cp_stats_free_peer_stats_info_ext() - API to free peer stats info ext
959   * structure
960   * @ev: structure from where peer stats info ext needs to be freed
961   *
962   * Return: none
963   */
ucfg_mc_cp_stats_free_peer_stats_info_ext(struct stats_event * ev)964  static void ucfg_mc_cp_stats_free_peer_stats_info_ext(struct stats_event *ev)
965  {
966  	struct peer_stats_info_ext_event *peer_stats_info =
967  							ev->peer_stats_info_ext;
968  	uint16_t i;
969  
970  	for (i = 0; i < ev->num_peer_stats_info_ext; i++) {
971  		qdf_mem_free(peer_stats_info->tx_pkt_per_mcs);
972  		qdf_mem_free(peer_stats_info->rx_pkt_per_mcs);
973  		peer_stats_info++;
974  	}
975  
976  	qdf_mem_free(ev->peer_stats_info_ext);
977  }
978  
ucfg_mc_cp_stats_free_stats_resources(struct stats_event * ev)979  void ucfg_mc_cp_stats_free_stats_resources(struct stats_event *ev)
980  {
981  	if (!ev)
982  		return;
983  
984  	qdf_mem_free(ev->pdev_stats);
985  	qdf_mem_free(ev->pdev_extd_stats);
986  	qdf_mem_free(ev->peer_adv_stats);
987  	qdf_mem_free(ev->peer_stats);
988  	qdf_mem_free(ev->cca_stats);
989  	qdf_mem_free(ev->vdev_summary_stats);
990  	qdf_mem_free(ev->vdev_chain_rssi);
991  	qdf_mem_free(ev->peer_extended_stats);
992  	ucfg_mc_cp_stats_free_peer_stats_info_ext(ev);
993  	qdf_mem_free(ev->vdev_extd_stats);
994  	qdf_mem_zero(ev, sizeof(*ev));
995  }
996  
ucfg_mc_cp_stats_cca_stats_get(struct wlan_objmgr_vdev * vdev,struct cca_stats * cca_stats)997  QDF_STATUS ucfg_mc_cp_stats_cca_stats_get(struct wlan_objmgr_vdev *vdev,
998  					  struct cca_stats *cca_stats)
999  {
1000  	struct vdev_cp_stats *vdev_cp_stats_priv;
1001  	struct vdev_mc_cp_stats *vdev_mc_stats;
1002  
1003  	vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev);
1004  	if (!vdev_cp_stats_priv) {
1005  		cp_stats_err("vdev cp stats object is null");
1006  		return QDF_STATUS_E_NULL_VALUE;
1007  	}
1008  
1009  	wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv);
1010  	vdev_mc_stats = vdev_cp_stats_priv->vdev_stats;
1011  	cca_stats->congestion = vdev_mc_stats->cca.congestion;
1012  	wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv);
1013  	return QDF_STATUS_SUCCESS;
1014  }
1015  
ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev * vdev,uint32_t flags)1016  QDF_STATUS ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev,
1017  					   uint32_t flags)
1018  {
1019  	struct vdev_mc_cp_stats *vdev_mc_stats;
1020  	struct vdev_cp_stats *vdev_cp_stats_priv;
1021  
1022  	vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev);
1023  	if (!vdev_cp_stats_priv) {
1024  		cp_stats_err("vdev cp stats object is null");
1025  		return QDF_STATUS_E_NULL_VALUE;
1026  	}
1027  
1028  	wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv);
1029  	vdev_mc_stats = vdev_cp_stats_priv->vdev_stats;
1030  	vdev_mc_stats->tx_rate_flags = flags;
1031  	wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv);
1032  
1033  	return QDF_STATUS_SUCCESS;
1034  }
1035  
ucfg_mc_cp_stats_register_lost_link_info_cb(struct wlan_objmgr_psoc * psoc,void (* lost_link_cp_stats_info_cb)(void * stats_ev))1036  void ucfg_mc_cp_stats_register_lost_link_info_cb(
1037  			struct wlan_objmgr_psoc *psoc,
1038  			void (*lost_link_cp_stats_info_cb)(void *stats_ev))
1039  {
1040  	struct psoc_cp_stats *psoc_cp_stats_priv;
1041  
1042  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
1043  	if (!psoc_cp_stats_priv) {
1044  		cp_stats_err("psoc cp stats object is null");
1045  		return;
1046  	}
1047  
1048  	psoc_cp_stats_priv->legacy_stats_cb = lost_link_cp_stats_info_cb;
1049  }
1050  
1051  #ifdef QCA_SUPPORT_CP_STATS
wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,qdf_freq_t req_freq)1052  uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc,
1053  					 uint8_t vdev_id, qdf_freq_t req_freq)
1054  {
1055  	struct wlan_objmgr_pdev *pdev;
1056  	struct wlan_objmgr_vdev *vdev;
1057  	struct pdev_cp_stats *pdev_cp_stats_priv;
1058  	struct per_channel_stats *channel_stats;
1059  	struct channel_status *channel_status_list;
1060  	uint8_t total_channel, chan_load = 0;
1061  	uint8_t i;
1062  	uint32_t rx_clear_count = 0, cycle_count = 0;
1063  	bool found = false;
1064  
1065  	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1066  						    WLAN_CP_STATS_ID);
1067  	if (!vdev)
1068  		return 0;
1069  
1070  	pdev = wlan_vdev_get_pdev(vdev);
1071  	if (!pdev) {
1072  		cp_stats_err("pdev object is null");
1073  		goto release_ref;
1074  	}
1075  
1076  	pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
1077  	if (!pdev_cp_stats_priv) {
1078  		cp_stats_err("pdev cp stats object is null");
1079  		goto release_ref;
1080  	}
1081  
1082  	channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats;
1083  	channel_status_list = channel_stats->channel_status_list;
1084  	total_channel = channel_stats->total_channel;
1085  
1086  	for (i = 0; i < total_channel; i++) {
1087  		if (channel_status_list[i].channel_freq == req_freq) {
1088  			rx_clear_count = channel_status_list[i].rx_clear_count;
1089  			cycle_count = channel_status_list[i].cycle_count;
1090  			found = true;
1091  			break;
1092  		}
1093  	}
1094  
1095  	if (!found) {
1096  		cp_stats_debug("no channel found for freq:%d", req_freq);
1097  		goto release_ref;
1098  	}
1099  
1100  	if (cycle_count == 0) {
1101  		cp_stats_debug("cycle_count is zero");
1102  		goto release_ref;
1103  	}
1104  
1105  	chan_load = ((rx_clear_count * 255) / cycle_count);
1106  
1107  	cp_stats_debug("t_chan:%d, freq:%d, rcc:%u, cc:%u, chan_load:%d",
1108  		       total_channel, req_freq, rx_clear_count, cycle_count,
1109  		       chan_load);
1110  
1111  release_ref:
1112  	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
1113  	return chan_load;
1114  }
1115  #endif
1116  
1117  #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD
1118  static QDF_STATUS
ucfg_mc_cp_stats_suspend_req_handler(struct wlan_objmgr_psoc * psoc)1119  ucfg_mc_cp_stats_suspend_req_handler(struct wlan_objmgr_psoc *psoc)
1120  {
1121  	struct psoc_mc_cp_stats *psoc_mc_stats;
1122  	struct psoc_cp_stats *psoc_cp_stats_priv;
1123  
1124  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
1125  	if (!psoc_cp_stats_priv) {
1126  		cp_stats_err("psoc cp stats object is null");
1127  		return QDF_STATUS_E_NULL_VALUE;
1128  	}
1129  
1130  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
1131  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
1132  	psoc_mc_stats->is_cp_stats_suspended = true;
1133  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
1134  
1135  	return QDF_STATUS_SUCCESS;
1136  }
1137  
1138  static QDF_STATUS
ucfg_mc_cp_stats_resume_req_handler(struct wlan_objmgr_psoc * psoc)1139  ucfg_mc_cp_stats_resume_req_handler(struct wlan_objmgr_psoc *psoc)
1140  {
1141  	struct psoc_mc_cp_stats *psoc_mc_stats;
1142  	struct psoc_cp_stats *psoc_cp_stats_priv;
1143  
1144  	psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc);
1145  	if (!psoc_cp_stats_priv) {
1146  		cp_stats_err("psoc cp stats object is null");
1147  		return QDF_STATUS_E_NULL_VALUE;
1148  	}
1149  
1150  	wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv);
1151  	psoc_mc_stats = psoc_cp_stats_priv->obj_stats;
1152  	psoc_mc_stats->is_cp_stats_suspended = false;
1153  	wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv);
1154  
1155  	return QDF_STATUS_SUCCESS;
1156  }
1157  
1158  static QDF_STATUS
ucfg_mc_cp_stats_resume_handler(struct wlan_objmgr_psoc * psoc,void * arg)1159  ucfg_mc_cp_stats_resume_handler(struct wlan_objmgr_psoc *psoc,
1160  				void *arg)
1161  {
1162  	return ucfg_mc_cp_stats_resume_req_handler(psoc);
1163  }
1164  
1165  static QDF_STATUS
ucfg_mc_cp_stats_suspend_handler(struct wlan_objmgr_psoc * psoc,void * arg)1166  ucfg_mc_cp_stats_suspend_handler(struct wlan_objmgr_psoc *psoc,
1167  				 void *arg)
1168  {
1169  	return ucfg_mc_cp_stats_suspend_req_handler(psoc);
1170  }
1171  
ucfg_mc_cp_stats_register_pmo_handler(void)1172  void ucfg_mc_cp_stats_register_pmo_handler(void)
1173  {
1174  	pmo_register_suspend_handler(WLAN_UMAC_COMP_CP_STATS,
1175  				     ucfg_mc_cp_stats_suspend_handler, NULL);
1176  	pmo_register_resume_handler(WLAN_UMAC_COMP_CP_STATS,
1177  				    ucfg_mc_cp_stats_resume_handler, NULL);
1178  }
1179  
1180  /**
1181   * wlan_cp_stats_get_ch_width_from_chan_info - get ch_width as per num channel
1182   * present in scan event
1183   * @channel_stat: struct scan_chan_info
1184   *
1185   * Return: phy_ch_width.
1186   */
1187  static enum phy_ch_width
wlan_cp_stats_get_ch_width_from_chan_info(struct channel_status * channel_stat)1188  wlan_cp_stats_get_ch_width_from_chan_info(struct channel_status *channel_stat)
1189  {
1190  	enum phy_ch_width scanned_ch_width;
1191  
1192  	switch (channel_stat->subband_info.num_chan) {
1193  	case 1:
1194  		scanned_ch_width = CH_WIDTH_20MHZ;
1195  		break;
1196  	case 2:
1197  		scanned_ch_width = CH_WIDTH_40MHZ;
1198  		break;
1199  	case 4:
1200  		scanned_ch_width = CH_WIDTH_80MHZ;
1201  		break;
1202  	case 8:
1203  		scanned_ch_width = CH_WIDTH_160MHZ;
1204  		break;
1205  	default:
1206  		scanned_ch_width = CH_WIDTH_INVALID;
1207  		break;
1208  	}
1209  
1210  	return scanned_ch_width;
1211  }
1212  
1213  /**
1214   * wlan_cp_stats_update_per_channel_stats - update per channel stats as per
1215   * data present in scan event
1216   * @channel_stats: per channel stats
1217   * @ev_channel_stat: channel stats per scan event
1218   * @freq: freq to update channel stats
1219   * @rx_clear_count: rx clear count for a freq
1220   *
1221   * Return: none.
1222   */
1223  static void
wlan_cp_stats_update_per_channel_stats(struct per_channel_stats * channel_stats,struct channel_status * ev_channel_stat,uint32_t freq,uint32_t rx_clear_count)1224  wlan_cp_stats_update_per_channel_stats(struct per_channel_stats *channel_stats,
1225  				       struct channel_status *ev_channel_stat,
1226  				       uint32_t freq, uint32_t rx_clear_count)
1227  {
1228  	struct channel_status *channel_status_list;
1229  	uint8_t total_channel, i;
1230  	bool found = false;
1231  
1232  	channel_status_list = channel_stats->channel_status_list;
1233  	total_channel = channel_stats->total_channel;
1234  
1235  	for (i = 0; i < total_channel; i++) {
1236  		if (channel_status_list[i].channel_freq == freq) {
1237  			cp_stats_debug("update rcc: %d, cc:%d at index: %d, freq: %d",
1238  				       ev_channel_stat->rx_clear_count,
1239  				       ev_channel_stat->cycle_count, i, freq);
1240  
1241  			channel_status_list[i].rx_clear_count = rx_clear_count;
1242  			channel_status_list[i].cycle_count =
1243  					ev_channel_stat->cycle_count;
1244  			found = true;
1245  			break;
1246  		}
1247  	}
1248  
1249  	if (!found) {
1250  		if (total_channel < NUM_CHANNELS) {
1251  			ev_channel_stat->rx_clear_count = rx_clear_count;
1252  			ev_channel_stat->channel_freq = freq;
1253  
1254  			cp_stats_debug("Add rcc: %d cc: %d, at index: %d, freq: %d",
1255  				       ev_channel_stat->rx_clear_count,
1256  				       ev_channel_stat->rx_clear_count,
1257  				       total_channel, freq);
1258  
1259  			qdf_mem_copy(&channel_status_list[total_channel++],
1260  				     ev_channel_stat,
1261  				     sizeof(*channel_status_list));
1262  			channel_stats->total_channel = total_channel;
1263  		} else {
1264  			cp_stats_debug("Chan cnt exceed, channel_id: %d",
1265  				       ev_channel_stat->channel_id);
1266  		}
1267  	}
1268  }
1269  
1270  /**
1271   * wlan_cp_stats_update_channel_stats - wrapper api to update per channel stats
1272   * as per data present in scan event
1273   * @channel_stats: per channel stats
1274   * @ev_channel_stat: channel stats per scan event
1275   *
1276   * Return: none.
1277   */
1278  static void
wlan_cp_stats_update_channel_stats(struct per_channel_stats * channel_stats,struct channel_status * ev_channel_stat)1279  wlan_cp_stats_update_channel_stats(struct per_channel_stats *channel_stats,
1280  				   struct channel_status *ev_channel_stat)
1281  {
1282  	uint8_t index, freq_info_num;
1283  	enum phy_ch_width scanned_ch_width;
1284  	const struct bonded_channel_freq *range = NULL;
1285  	uint16_t start_freq, end_freq;
1286  	uint32_t rx_clear_count;
1287  
1288  	scanned_ch_width =
1289  		wlan_cp_stats_get_ch_width_from_chan_info(ev_channel_stat);
1290  	if (scanned_ch_width == CH_WIDTH_INVALID) {
1291  		cp_stats_debug("Invalid scanned_ch_width");
1292  		return;
1293  	}
1294  
1295  	if (scanned_ch_width == CH_WIDTH_20MHZ) {
1296  		start_freq = ev_channel_stat->channel_freq;
1297  		end_freq = ev_channel_stat->channel_freq;
1298  	} else {
1299  		range =
1300  		   wlan_reg_get_bonded_chan_entry(ev_channel_stat->channel_freq,
1301  						  scanned_ch_width, 0);
1302  		if (!range) {
1303  			cp_stats_debug("range is NULL for freq %d, ch_width %d",
1304  				       ev_channel_stat->channel_freq,
1305  				       scanned_ch_width);
1306  			return;
1307  		}
1308  		start_freq = range->start_freq;
1309  		end_freq = range->end_freq;
1310  	}
1311  
1312  	freq_info_num = ev_channel_stat->subband_info.num_chan;
1313  	index = 0;
1314  
1315  	cp_stats_debug("freq :%d bw %d, range [%d-%d], num_freq:%d",
1316  		       ev_channel_stat->channel_freq, scanned_ch_width,
1317  		       start_freq, end_freq, freq_info_num);
1318  
1319  	for (; start_freq <= end_freq;) {
1320  		if (index >= freq_info_num || index >= MAX_WIDE_BAND_SCAN_CHAN)
1321  			break;
1322  		rx_clear_count =
1323  		    ev_channel_stat->subband_info.cca_busy_subband_info[index];
1324  		wlan_cp_stats_update_per_channel_stats(channel_stats,
1325  						       ev_channel_stat,
1326  						       start_freq,
1327  						       rx_clear_count);
1328  
1329  		start_freq += BW_20_MHZ;
1330  		index++;
1331  	}
1332  }
1333  
wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc * psoc,struct channel_status * ev_channel_stat,uint8_t vdev_id)1334  void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc,
1335  				    struct channel_status *ev_channel_stat,
1336  				    uint8_t vdev_id)
1337  {
1338  	struct wlan_objmgr_pdev *pdev;
1339  	struct wlan_objmgr_vdev *vdev;
1340  	struct pdev_cp_stats *pdev_cp_stats_priv;
1341  	struct per_channel_stats *channel_stats;
1342  	struct channel_status *channel_status_list;
1343  	uint8_t total_channel;
1344  	uint8_t i;
1345  	bool found = false;
1346  
1347  	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
1348  						    WLAN_CP_STATS_ID);
1349  	if (!vdev)
1350  		return;
1351  
1352  	pdev = wlan_vdev_get_pdev(vdev);
1353  	if (!pdev) {
1354  		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
1355  		cp_stats_err("pdev object is null");
1356  		return;
1357  	}
1358  
1359  	pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
1360  	if (!pdev_cp_stats_priv) {
1361  		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
1362  		cp_stats_err("pdev cp stats object is null");
1363  		return;
1364  	}
1365  
1366  	channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats;
1367  	channel_status_list = channel_stats->channel_status_list;
1368  	total_channel = channel_stats->total_channel;
1369  
1370  	if (ev_channel_stat->subband_info.is_wide_band_scan) {
1371  		wlan_cp_stats_update_channel_stats(channel_stats,
1372  						   ev_channel_stat);
1373  		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
1374  		return;
1375  	}
1376  
1377  	for (i = 0; i < total_channel; i++) {
1378  		if (channel_status_list[i].channel_id ==
1379  		    ev_channel_stat->channel_id) {
1380  			if (ev_channel_stat->cmd_flags ==
1381  			    WMI_CHAN_InFO_END_RESP &&
1382  			    channel_status_list[i].cmd_flags ==
1383  			    WMI_CHAN_InFO_START_RESP) {
1384  				/* adjust to delta value for counts */
1385  				ev_channel_stat->rx_clear_count -=
1386  				    channel_status_list[i].rx_clear_count;
1387  				ev_channel_stat->cycle_count -=
1388  				    channel_status_list[i].cycle_count;
1389  				ev_channel_stat->rx_frame_count -=
1390  				    channel_status_list[i].rx_frame_count;
1391  				ev_channel_stat->tx_frame_count -=
1392  				    channel_status_list[i].tx_frame_count;
1393  				ev_channel_stat->bss_rx_cycle_count -=
1394  				    channel_status_list[i].bss_rx_cycle_count;
1395  			}
1396  			qdf_mem_copy(&channel_status_list[i], ev_channel_stat,
1397  				     sizeof(*channel_status_list));
1398  			found = true;
1399  			break;
1400  		}
1401  	}
1402  
1403  	if (!found) {
1404  		if (total_channel < NUM_CHANNELS) {
1405  			qdf_mem_copy(&channel_status_list[total_channel++],
1406  				     ev_channel_stat,
1407  				     sizeof(*channel_status_list));
1408  			channel_stats->total_channel = total_channel;
1409  		} else {
1410  			cp_stats_err("Chan cnt exceed, channel_id=%d",
1411  				     ev_channel_stat->channel_id);
1412  		}
1413  	}
1414  
1415  	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
1416  }
1417  
1418  struct channel_status *
ucfg_mc_cp_stats_get_channel_status(struct wlan_objmgr_pdev * pdev,uint32_t chan_freq)1419  ucfg_mc_cp_stats_get_channel_status(struct wlan_objmgr_pdev *pdev,
1420  				    uint32_t chan_freq)
1421  {
1422  	struct pdev_cp_stats *pdev_cp_stats_priv;
1423  	struct per_channel_stats *channel_stats;
1424  	struct channel_status *entry;
1425  	uint8_t i;
1426  
1427  	pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
1428  	if (!pdev_cp_stats_priv) {
1429  		cp_stats_err("pdev cp stats object is null");
1430  		return NULL;
1431  	}
1432  
1433  	channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats;
1434  
1435  	for (i = 0; i < channel_stats->total_channel; i++) {
1436  		entry = &channel_stats->channel_status_list[i];
1437  		if (entry->channel_freq == chan_freq)
1438  			return entry;
1439  	}
1440  	cp_stats_err("Channel %d status info not exist", chan_freq);
1441  
1442  	return NULL;
1443  }
1444  
ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev * pdev)1445  void ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev *pdev)
1446  {
1447  	struct pdev_cp_stats *pdev_cp_stats_priv;
1448  	struct per_channel_stats *channel_stats;
1449  
1450  	pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev);
1451  	if (!pdev_cp_stats_priv) {
1452  		cp_stats_err("pdev cp stats object is null");
1453  		return;
1454  	}
1455  
1456  	channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats;
1457  	channel_stats->total_channel = 0;
1458  }
1459  
1460  #endif
1461