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