xref: /wlan-driver/qca-wifi-host-cmn/umac/cp_stats/core/src/wlan_cp_stats_comp_handler.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2018 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 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_comp_handler.c
22  *
23  * This file maintain definitions to APIs which handle attach/detach of other
24  * UMAC component specific cp stat object to cp stats
25  *
26  * Components calling configure API should alloc data structure while attaching
27  * dealloc while detaching, where as address for which to be deallocated will
28  * be passed back to component for data
29  */
30 #include "wlan_cp_stats_comp_handler.h"
31 #include "wlan_cp_stats_defs.h"
32 #include <wlan_cp_stats_ucfg_api.h>
33 #include <wlan_cp_stats_utils_api.h>
34 #include <wmi_unified_twt_param.h>
35 #include <wlan_twt_public_structs.h>
36 
37 
38 static QDF_STATUS
wlan_cp_stats_psoc_comp_obj_config(struct wlan_objmgr_psoc * psoc,enum wlan_cp_stats_comp_id comp_id,enum wlan_cp_stats_cfg_state cfg_state,void * data)39 wlan_cp_stats_psoc_comp_obj_config
40 (struct wlan_objmgr_psoc *psoc, enum wlan_cp_stats_comp_id comp_id,
41 	enum wlan_cp_stats_cfg_state cfg_state, void *data)
42 {
43 	struct psoc_cp_stats *psoc_cs;
44 
45 	psoc_cs = wlan_cp_stats_get_psoc_stats_obj(psoc);
46 	if (!psoc_cs) {
47 		cp_stats_err("psoc cp stats object is null");
48 		return QDF_STATUS_E_INVAL;
49 	}
50 
51 	wlan_cp_stats_psoc_obj_lock(psoc_cs);
52 	if (cfg_state == WLAN_CP_STATS_OBJ_ATTACH) {
53 		if (psoc_cs->psoc_comp_priv_obj[comp_id]) {
54 			wlan_cp_stats_psoc_obj_unlock(psoc_cs);
55 			return QDF_STATUS_E_EXISTS;
56 		}
57 		psoc_cs->psoc_comp_priv_obj[comp_id] = data;
58 	} else if (cfg_state == WLAN_CP_STATS_OBJ_DETACH) {
59 		if (psoc_cs->psoc_comp_priv_obj[comp_id] != data) {
60 			wlan_cp_stats_psoc_obj_unlock(psoc_cs);
61 			return QDF_STATUS_E_INVAL;
62 		}
63 		data = psoc_cs->psoc_comp_priv_obj[comp_id];
64 		psoc_cs->psoc_comp_priv_obj[comp_id] = NULL;
65 	} else if (cfg_state == WLAN_CP_STATS_OBJ_INVALID) {
66 		cp_stats_err("Invalid cp stats cfg_state");
67 		wlan_cp_stats_psoc_obj_unlock(psoc_cs);
68 		return QDF_STATUS_E_INVAL;
69 	}
70 
71 	wlan_cp_stats_psoc_obj_unlock(psoc_cs);
72 	return QDF_STATUS_SUCCESS;
73 }
74 
75 static QDF_STATUS
wlan_cp_stats_pdev_comp_obj_config(struct wlan_objmgr_pdev * pdev,enum wlan_cp_stats_comp_id comp_id,enum wlan_cp_stats_cfg_state cfg_state,void * data)76 wlan_cp_stats_pdev_comp_obj_config
77 (struct wlan_objmgr_pdev *pdev, enum wlan_cp_stats_comp_id comp_id,
78 	enum wlan_cp_stats_cfg_state cfg_state, void *data)
79 {
80 	struct pdev_cp_stats *pdev_cs;
81 
82 	pdev_cs = wlan_cp_stats_get_pdev_stats_obj(pdev);
83 	if (!pdev_cs) {
84 		cp_stats_err("pdev cp stats object is null");
85 		return QDF_STATUS_E_INVAL;
86 	}
87 
88 	wlan_cp_stats_pdev_obj_lock(pdev_cs);
89 	if (cfg_state == WLAN_CP_STATS_OBJ_ATTACH) {
90 		if (pdev_cs->pdev_comp_priv_obj[comp_id]) {
91 			wlan_cp_stats_pdev_obj_unlock(pdev_cs);
92 			return QDF_STATUS_E_EXISTS;
93 		}
94 		pdev_cs->pdev_comp_priv_obj[comp_id] = data;
95 	} else if (cfg_state == WLAN_CP_STATS_OBJ_DETACH) {
96 		if (pdev_cs->pdev_comp_priv_obj[comp_id] != data) {
97 			wlan_cp_stats_pdev_obj_unlock(pdev_cs);
98 			return QDF_STATUS_E_INVAL;
99 		}
100 		data = pdev_cs->pdev_comp_priv_obj[comp_id];
101 		pdev_cs->pdev_comp_priv_obj[comp_id] = NULL;
102 	} else if (cfg_state == WLAN_CP_STATS_OBJ_INVALID) {
103 		cp_stats_err("Invalid cp stats cfg_state");
104 		wlan_cp_stats_pdev_obj_unlock(pdev_cs);
105 		return QDF_STATUS_E_INVAL;
106 	}
107 
108 	wlan_cp_stats_pdev_obj_unlock(pdev_cs);
109 	return QDF_STATUS_SUCCESS;
110 }
111 
112 static QDF_STATUS
wlan_cp_stats_vdev_comp_obj_config(struct wlan_objmgr_vdev * vdev,enum wlan_cp_stats_comp_id comp_id,enum wlan_cp_stats_cfg_state cfg_state,void * data)113 wlan_cp_stats_vdev_comp_obj_config
114 (struct wlan_objmgr_vdev *vdev, enum wlan_cp_stats_comp_id comp_id,
115 	enum wlan_cp_stats_cfg_state cfg_state, void *data)
116 {
117 	struct vdev_cp_stats *vdev_cs;
118 
119 	vdev_cs = wlan_cp_stats_get_vdev_stats_obj(vdev);
120 	if (!vdev_cs) {
121 		cp_stats_err("vdev cp stats object is null");
122 		return QDF_STATUS_E_INVAL;
123 	}
124 
125 	wlan_cp_stats_vdev_obj_lock(vdev_cs);
126 	if (cfg_state == WLAN_CP_STATS_OBJ_ATTACH) {
127 		if (vdev_cs->vdev_comp_priv_obj[comp_id]) {
128 			wlan_cp_stats_vdev_obj_unlock(vdev_cs);
129 			return QDF_STATUS_E_EXISTS;
130 		}
131 		vdev_cs->vdev_comp_priv_obj[comp_id] = data;
132 	} else if (cfg_state == WLAN_CP_STATS_OBJ_DETACH) {
133 		if (vdev_cs->vdev_comp_priv_obj[comp_id] != data) {
134 			wlan_cp_stats_vdev_obj_unlock(vdev_cs);
135 			return QDF_STATUS_E_INVAL;
136 		}
137 		data = vdev_cs->vdev_comp_priv_obj[comp_id];
138 		vdev_cs->vdev_comp_priv_obj[comp_id] = NULL;
139 	} else if (cfg_state == WLAN_CP_STATS_OBJ_INVALID) {
140 		cp_stats_err("Invalid cp stats cfg_state");
141 		wlan_cp_stats_vdev_obj_unlock(vdev_cs);
142 		return QDF_STATUS_E_INVAL;
143 	}
144 
145 	wlan_cp_stats_vdev_obj_unlock(vdev_cs);
146 	return QDF_STATUS_SUCCESS;
147 }
148 
149 static QDF_STATUS
wlan_cp_stats_peer_comp_obj_config(struct wlan_objmgr_peer * peer,enum wlan_cp_stats_comp_id comp_id,enum wlan_cp_stats_cfg_state cfg_state,void * data)150 wlan_cp_stats_peer_comp_obj_config
151 (struct wlan_objmgr_peer *peer, enum wlan_cp_stats_comp_id comp_id,
152 	enum wlan_cp_stats_cfg_state cfg_state, void *data)
153 {
154 	struct peer_cp_stats *peer_cs;
155 
156 	peer_cs = wlan_cp_stats_get_peer_stats_obj(peer);
157 	if (!peer_cs) {
158 		cp_stats_err("peer cp stats object is null");
159 		return QDF_STATUS_E_INVAL;
160 	}
161 
162 	wlan_cp_stats_peer_obj_lock(peer_cs);
163 	if (cfg_state == WLAN_CP_STATS_OBJ_ATTACH) {
164 		if (peer_cs->peer_comp_priv_obj[comp_id]) {
165 			wlan_cp_stats_peer_obj_unlock(peer_cs);
166 			return QDF_STATUS_E_EXISTS;
167 		}
168 		peer_cs->peer_comp_priv_obj[comp_id] = data;
169 	} else if (cfg_state == WLAN_CP_STATS_OBJ_DETACH) {
170 		if (peer_cs->peer_comp_priv_obj[comp_id] != data) {
171 			wlan_cp_stats_peer_obj_unlock(peer_cs);
172 			return QDF_STATUS_E_INVAL;
173 		}
174 		data = peer_cs->peer_comp_priv_obj[comp_id];
175 		peer_cs->peer_comp_priv_obj[comp_id] = NULL;
176 	} else if (cfg_state == WLAN_CP_STATS_OBJ_INVALID) {
177 		cp_stats_err("Invalid cp stats cfg_state");
178 		wlan_cp_stats_peer_obj_unlock(peer_cs);
179 		return QDF_STATUS_E_INVAL;
180 	}
181 
182 	wlan_cp_stats_peer_obj_unlock(peer_cs);
183 	return QDF_STATUS_SUCCESS;
184 }
185 
186 QDF_STATUS
wlan_cp_stats_comp_obj_config(enum wlan_objmgr_obj_type obj_type,enum wlan_cp_stats_cfg_state cfg_state,enum wlan_cp_stats_comp_id comp_id,void * cmn_obj,void * data)187 wlan_cp_stats_comp_obj_config(enum wlan_objmgr_obj_type obj_type,
188 			      enum wlan_cp_stats_cfg_state cfg_state,
189 			      enum wlan_cp_stats_comp_id comp_id,
190 			      void *cmn_obj, void *data)
191 {
192 	QDF_STATUS status;
193 
194 	if (!cmn_obj) {
195 		cp_stats_err("Common object is NULL");
196 		return QDF_STATUS_E_INVAL;
197 	}
198 
199 	/* component id is invalid */
200 	if (comp_id >= WLAN_CP_STATS_MAX_COMPONENTS) {
201 		cp_stats_err("Invalid component Id");
202 		return QDF_STATUS_MAXCOMP_FAIL;
203 	}
204 
205 	switch (obj_type) {
206 	case WLAN_PSOC_OP:
207 		status =
208 			wlan_cp_stats_psoc_comp_obj_config(
209 					(struct wlan_objmgr_psoc *)cmn_obj,
210 					comp_id, cfg_state, data);
211 		break;
212 	case WLAN_PDEV_OP:
213 		status =
214 			wlan_cp_stats_pdev_comp_obj_config(
215 					(struct wlan_objmgr_pdev *)cmn_obj,
216 					comp_id, cfg_state, data);
217 		break;
218 	case WLAN_VDEV_OP:
219 		status =
220 			wlan_cp_stats_vdev_comp_obj_config(
221 					(struct wlan_objmgr_vdev *)cmn_obj,
222 					comp_id, cfg_state, data);
223 		break;
224 	case WLAN_PEER_OP:
225 		status =
226 			wlan_cp_stats_peer_comp_obj_config(
227 					(struct wlan_objmgr_peer *)cmn_obj,
228 					comp_id, cfg_state, data);
229 		break;
230 	default:
231 		cp_stats_err("Invalid common object");
232 		return QDF_STATUS_E_INVAL;
233 	}
234 
235 	return status;
236 }
237 
238 #if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED)
239 QDF_STATUS
wlan_cp_stats_twt_get_session_evt_handler(struct wlan_objmgr_psoc * psoc,struct twt_session_stats_info * twt_params)240 wlan_cp_stats_twt_get_session_evt_handler(
241 				struct wlan_objmgr_psoc *psoc,
242 				struct twt_session_stats_info *twt_params)
243 {
244 	int i;
245 	uint32_t event_type;
246 	struct wlan_objmgr_peer *peer;
247 	struct peer_cp_stats *peer_cp_stats_priv;
248 	QDF_STATUS status = QDF_STATUS_SUCCESS;
249 
250 	if (!psoc || !twt_params)
251 		return QDF_STATUS_E_INVAL;
252 
253 	peer = wlan_objmgr_get_peer_by_mac(psoc, twt_params->peer_mac.bytes,
254 					   WLAN_CP_STATS_ID);
255 	if (!peer) {
256 		cp_stats_err("peer is NULL");
257 		return QDF_STATUS_E_INVAL;
258 	}
259 
260 	peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
261 	if (!peer_cp_stats_priv) {
262 		cp_stats_err("peer_cp_stats_priv is null");
263 		status = QDF_STATUS_E_INVAL;
264 		goto cleanup;
265 	}
266 
267 	if (twt_params->event_type == HOST_TWT_SESSION_UPDATE ||
268 	    twt_params->event_type == HOST_TWT_SESSION_TEARDOWN) {
269 		/* Update for a existing session, find by dialog_id */
270 		for (i = 0; i < WLAN_MAX_TWT_SESSIONS_PER_PEER; i++) {
271 			if (peer_cp_stats_priv->twt_param[i].dialog_id !=
272 			    twt_params->dialog_id)
273 				continue;
274 			qdf_mem_copy(&peer_cp_stats_priv->twt_param[i],
275 				     twt_params, sizeof(*twt_params));
276 			goto cleanup;
277 		}
278 	} else if (twt_params->event_type == HOST_TWT_SESSION_SETUP) {
279 		/* New session, fill in any existing invalid session */
280 		for (i = 0; i < WLAN_MAX_TWT_SESSIONS_PER_PEER; i++) {
281 			event_type =
282 				peer_cp_stats_priv->twt_param[i].event_type;
283 			if (event_type != HOST_TWT_SESSION_SETUP &&
284 			    event_type != HOST_TWT_SESSION_UPDATE) {
285 				qdf_mem_copy(&peer_cp_stats_priv->twt_param[i],
286 					     twt_params, sizeof(*twt_params));
287 				goto cleanup;
288 			}
289 		}
290 	}
291 
292 	cp_stats_err("Unable to save twt session params with dialog id %d",
293 		     twt_params->dialog_id);
294 	status = QDF_STATUS_E_INVAL;
295 
296 cleanup:
297 	wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
298 	return status;
299 }
300 #endif
301