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