1 /* 2 * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: target_if_cp_stats.c 21 * 22 * This file provide definition for APIs registered through lmac Tx Ops 23 */ 24 25 #include <qdf_mem.h> 26 #include <qdf_status.h> 27 #include <target_if_cp_stats.h> 28 #include <wmi_unified_priv.h> 29 #include <wmi_unified_param.h> 30 #include <target_if.h> 31 #include <wlan_tgt_def_config.h> 32 #include <wmi_unified_api.h> 33 #include <wlan_osif_priv.h> 34 #include <wlan_cp_stats_utils_api.h> 35 36 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 37 38 uint32_t get_infra_cp_stats_id(enum infra_cp_stats_id type) 39 { 40 switch (type) { 41 case TYPE_REQ_CTRL_PATH_PDEV_TX_STAT: 42 return WMI_REQUEST_CTRL_PATH_PDEV_TX_STAT; 43 case TYPE_REQ_CTRL_PATH_VDEV_EXTD_STAT: 44 return WMI_REQUEST_CTRL_PATH_VDEV_EXTD_STAT; 45 case TYPE_REQ_CTRL_PATH_MEM_STAT: 46 return WMI_REQUEST_CTRL_PATH_MEM_STAT; 47 case TYPE_REQ_CTRL_PATH_TWT_STAT: 48 return WMI_REQUEST_CTRL_PATH_TWT_STAT; 49 default: 50 return -EINVAL; 51 } 52 } 53 54 uint32_t get_infra_cp_stats_action(enum infra_cp_stats_action action) 55 { 56 switch (action) { 57 case ACTION_REQ_CTRL_PATH_STAT_GET: 58 return WMI_REQUEST_CTRL_PATH_STAT_GET; 59 case ACTION_REQ_CTRL_PATH_STAT_RESET: 60 return WMI_REQUEST_CTRL_PATH_STAT_RESET; 61 case ACTION_REQ_CTRL_PATH_STAT_START: 62 return WMI_REQUEST_CTRL_PATH_STAT_START; 63 case ACTION_REQ_CTRL_PATH_STAT_STOP: 64 return WMI_REQUEST_CTRL_PATH_STAT_STOP; 65 default: 66 return -EINVAL; 67 } 68 } 69 70 #ifdef WLAN_SUPPORT_TWT 71 /** 72 * target_if_infra_cp_stats_twt_event_free() - Free event buffer 73 * @ev: pointer to infra cp stats event structure 74 * 75 * Return: None 76 */ 77 static 78 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev) 79 { 80 qdf_mem_free(ev->twt_infra_cp_stats); 81 ev->twt_infra_cp_stats = NULL; 82 } 83 84 /** 85 * target_if_infra_cp_stats_twt_event_alloc() - Allocate event buffer for TWT 86 * parameters 87 * @ev: pointer to infra cp stats event structure 88 * 89 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on 90 * failure 91 */ 92 static QDF_STATUS 93 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev) 94 { 95 ev->twt_infra_cp_stats = 96 qdf_mem_malloc(sizeof(*ev->twt_infra_cp_stats) * 97 INFRA_CP_STATS_MAX_RESP_TWT_DIALOG_ID); 98 if (!ev->twt_infra_cp_stats) { 99 cp_stats_err("mem alloc failed for ev.twt_infra_cp_stats"); 100 return QDF_STATUS_E_NOMEM; 101 } 102 103 return QDF_STATUS_SUCCESS; 104 } 105 #else 106 static inline 107 void target_if_infra_cp_stats_twt_event_free(struct infra_cp_stats_event *ev) 108 { 109 } 110 111 static inline QDF_STATUS 112 target_if_infra_cp_stats_twt_event_alloc(struct infra_cp_stats_event *ev) 113 { 114 return QDF_STATUS_SUCCESS; 115 } 116 117 static inline 118 void target_if_infra_cp_stats_free_stats_event(struct infra_cp_stats_event *ev) 119 { 120 } 121 #endif /* WLAN_SUPPORT_TWT */ 122 123 /** 124 * target_if_extract_infra_cp_stats_event() - Extract data from stats event 125 * @wmi_hdl: WMI Handle 126 * @data: pointer to event data buffer from firmware 127 * @data_len: length of the data buffer 128 * @ev: pointer of output structure to be filled with extracted values 129 * 130 * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes 131 * on failure 132 */ 133 static QDF_STATUS 134 target_if_extract_infra_cp_stats_event(struct wmi_unified *wmi_hdl, 135 uint8_t *data, uint32_t data_len, 136 struct infra_cp_stats_event *ev) 137 { 138 QDF_STATUS status; 139 uint32_t more_flag = 0; 140 141 status = wmi_unified_extract_cp_stats_more_pending(wmi_hdl, data, 142 &more_flag); 143 144 status = wmi_unified_extract_infra_cp_stats(wmi_hdl, data, 145 data_len, ev); 146 147 cp_stats_debug("request_id %d", ev->request_id); 148 149 return QDF_STATUS_SUCCESS; 150 } 151 152 /** 153 * target_if_infra_cp_stats_event_handler() - Handle 154 * wmi_pdev_cp_fwstats_eventid 155 * @scn: opaque scn handle 156 * @data: event buffer received from fw 157 * @datalen: length of event buffer 158 * 159 * Return: 0 for success or non zero error codes for failure 160 */ 161 static 162 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data, 163 uint32_t datalen) 164 { 165 QDF_STATUS status; 166 struct infra_cp_stats_event ev = {0}; 167 struct wlan_objmgr_psoc *psoc; 168 struct wmi_unified *wmi_handle; 169 struct wlan_lmac_if_cp_stats_rx_ops *rx_ops; 170 171 cp_stats_debug("Enter"); 172 173 if (!scn || !data) { 174 cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data); 175 return -EINVAL; 176 } 177 178 psoc = target_if_get_psoc_from_scn_hdl(scn); 179 if (!psoc) { 180 cp_stats_err("null psoc"); 181 return -EINVAL; 182 } 183 184 rx_ops = target_if_cp_stats_get_rx_ops(psoc); 185 if (!rx_ops || !rx_ops->process_stats_event) { 186 cp_stats_err("callback not registered"); 187 return -EINVAL; 188 } 189 190 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 191 if (!wmi_handle) { 192 cp_stats_err("wmi_handle is null"); 193 return -EINVAL; 194 } 195 status = target_if_infra_cp_stats_twt_event_alloc(&ev); 196 if (QDF_IS_STATUS_ERROR(status)) { 197 cp_stats_err("Alloc TWT event mem failed"); 198 goto end; 199 } 200 201 status = target_if_extract_infra_cp_stats_event(wmi_handle, data, 202 datalen, &ev); 203 if (QDF_IS_STATUS_ERROR(status)) { 204 cp_stats_err("extract event failed"); 205 goto end; 206 } 207 208 status = rx_ops->process_infra_stats_event(psoc, &ev); 209 210 end: 211 target_if_infra_cp_stats_twt_event_free(&ev); 212 213 return qdf_status_to_os_return(status); 214 } 215 #else 216 static 217 int target_if_infra_cp_stats_event_handler(ol_scn_t scn, uint8_t *data, 218 uint32_t datalen) 219 { 220 return 0; 221 } 222 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ 223 224 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 225 static QDF_STATUS 226 target_if_cp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc) 227 { 228 struct wmi_unified *wmi_handle; 229 QDF_STATUS ret_val; 230 231 if (!psoc) { 232 cp_stats_err("PSOC is NULL!"); 233 return QDF_STATUS_E_INVAL; 234 } 235 236 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 237 if (!wmi_handle) { 238 cp_stats_err("wmi_handle is null"); 239 return QDF_STATUS_E_INVAL; 240 } 241 242 ret_val = wmi_unified_register_event_handler(wmi_handle, 243 wmi_pdev_cp_fwstats_eventid, 244 target_if_infra_cp_stats_event_handler, 245 WMI_RX_WORK_CTX); 246 if (QDF_IS_STATUS_ERROR(ret_val)) 247 cp_stats_err("Failed to register for pdev_cp_fwstats_event"); 248 249 return QDF_STATUS_SUCCESS; 250 } 251 252 static QDF_STATUS 253 target_if_cp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc) 254 { 255 struct wmi_unified *wmi_handle; 256 257 if (!psoc) { 258 cp_stats_err("PSOC is NULL!"); 259 return QDF_STATUS_E_INVAL; 260 } 261 262 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 263 if (!wmi_handle) { 264 cp_stats_err("wmi_handle is null"); 265 return QDF_STATUS_E_INVAL; 266 } 267 268 wmi_unified_unregister_event_handler(wmi_handle, 269 wmi_pdev_cp_fwstats_eventid); 270 return QDF_STATUS_SUCCESS; 271 } 272 #else 273 static QDF_STATUS 274 target_if_cp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc) 275 { 276 if (!psoc) { 277 cp_stats_err("PSOC is NULL!"); 278 return QDF_STATUS_E_INVAL; 279 } 280 281 return QDF_STATUS_SUCCESS; 282 } 283 284 static QDF_STATUS 285 target_if_cp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc) 286 { 287 if (!psoc) { 288 cp_stats_err("PSOC is NULL!"); 289 return QDF_STATUS_E_INVAL; 290 } 291 292 return QDF_STATUS_SUCCESS; 293 } 294 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ 295 296 #ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS 297 /** 298 * target_if_infra_cp_stats_req() - API to send stats request to wmi 299 * @psoc: pointer to psoc object 300 * @req: pointer to object containing stats request parameters 301 * 302 * Return: QDF_STATUS_SUCCESS on success, else other qdf error values 303 */ 304 static 305 QDF_STATUS target_if_infra_cp_stats_req(struct wlan_objmgr_psoc *psoc, 306 struct infra_cp_stats_cmd_info *req) 307 308 { 309 struct wmi_unified *wmi_handle; 310 311 wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); 312 if (!wmi_handle) { 313 cp_stats_err("wmi_handle is null."); 314 return QDF_STATUS_E_NULL_VALUE; 315 } 316 317 return wmi_unified_infra_cp_stats_request_send(wmi_handle, req); 318 } 319 320 static void target_if_register_infra_cp_stats_txops( 321 struct wlan_lmac_if_cp_stats_tx_ops *tx_ops) 322 { 323 tx_ops->send_req_infra_cp_stats = target_if_infra_cp_stats_req; 324 } 325 #else 326 static void target_if_register_infra_cp_stats_txops( 327 struct wlan_lmac_if_cp_stats_tx_ops *tx_ops) 328 { 329 } 330 #endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ 331 332 QDF_STATUS 333 target_if_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) 334 { 335 struct wlan_lmac_if_cp_stats_tx_ops *cp_stats_tx_ops; 336 337 if (!tx_ops) { 338 cp_stats_err("lmac tx ops is NULL!"); 339 return QDF_STATUS_E_INVAL; 340 } 341 342 cp_stats_tx_ops = &tx_ops->cp_stats_tx_ops; 343 if (!cp_stats_tx_ops) { 344 cp_stats_err("lmac tx ops is NULL!"); 345 return QDF_STATUS_E_FAILURE; 346 } 347 target_if_register_infra_cp_stats_txops(cp_stats_tx_ops); 348 349 cp_stats_tx_ops->cp_stats_attach = 350 target_if_cp_stats_register_event_handler; 351 cp_stats_tx_ops->cp_stats_detach = 352 target_if_cp_stats_unregister_event_handler; 353 cp_stats_tx_ops->cp_stats_legacy_attach = 354 target_if_cp_stats_register_legacy_event_handler; 355 cp_stats_tx_ops->cp_stats_legacy_detach = 356 target_if_cp_stats_unregister_legacy_event_handler; 357 return QDF_STATUS_SUCCESS; 358 } 359