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 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 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 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 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 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 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