1 /* 2 * Copyright (c) 2018, 2020 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: This file contains ocb south bound interface definitions 22 */ 23 24 #include <scheduler_api.h> 25 #include <wlan_objmgr_psoc_obj.h> 26 #include <wlan_objmgr_global_obj.h> 27 #include <wlan_objmgr_pdev_obj.h> 28 #include <wlan_objmgr_vdev_obj.h> 29 #include "wlan_ocb_public_structs.h" 30 #include "wlan_ocb_ucfg_api.h" 31 #include "wlan_ocb_tgt_api.h" 32 #include "wlan_ocb_main.h" 33 34 /** 35 * wlan_ocb_flush_callback() - OCB message flash callback 36 * @msg: OCB message 37 * 38 * Return: QDF_STATUS_SUCCESS on success. 39 */ wlan_ocb_flush_callback(struct scheduler_msg * msg)40 static QDF_STATUS wlan_ocb_flush_callback(struct scheduler_msg *msg) 41 { 42 struct ocb_rx_event *event; 43 44 if (!msg) { 45 ocb_err("Null point for OCB message"); 46 return QDF_STATUS_E_INVAL; 47 } 48 49 event = msg->bodyptr; 50 wlan_ocb_release_rx_event(event); 51 52 return QDF_STATUS_SUCCESS; 53 } 54 55 /** 56 * tgt_ocb_channel_config_status() - handler for channel config response 57 * @psoc: psoc handle 58 * @status: status for last channel config 59 * 60 * Return: QDF_STATUS_SUCCESS on success 61 */ 62 static QDF_STATUS tgt_ocb_channel_config_status(struct wlan_objmgr_psoc * psoc,uint32_t status)63 tgt_ocb_channel_config_status(struct wlan_objmgr_psoc *psoc, 64 uint32_t status) 65 { 66 QDF_STATUS qdf_status; 67 struct scheduler_msg msg = {0}; 68 struct ocb_rx_event *event; 69 70 event = qdf_mem_malloc(sizeof(*event)); 71 if (!event) 72 return QDF_STATUS_E_NOMEM; 73 74 qdf_status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); 75 if (QDF_IS_STATUS_ERROR(qdf_status)) { 76 ocb_err("Failed to get psoc ref"); 77 wlan_ocb_release_rx_event(event); 78 return qdf_status; 79 } 80 event->psoc = psoc; 81 event->rsp.channel_cfg_rsp.status = status; 82 event->evt_id = OCB_CHANNEL_CONFIG_STATUS; 83 msg.type = OCB_CHANNEL_CONFIG_STATUS; 84 msg.bodyptr = event; 85 msg.callback = ocb_process_evt; 86 msg.flush_callback = wlan_ocb_flush_callback; 87 qdf_status = scheduler_post_message(QDF_MODULE_ID_OCB, 88 QDF_MODULE_ID_OCB, 89 QDF_MODULE_ID_TARGET_IF, &msg); 90 91 if (QDF_IS_STATUS_SUCCESS(qdf_status)) 92 return QDF_STATUS_SUCCESS; 93 94 ocb_err("failed to send OCB_CHANNEL_CONFIG_STATUS msg"); 95 wlan_ocb_release_rx_event(event); 96 97 return qdf_status; 98 } 99 100 /** 101 * tgt_ocb_get_tsf_timer() - handle for TSF timer response 102 * @psoc: psoc handle 103 * @response: TSF timer response 104 * 105 * Return: QDF_STATUS_SUCCESS on success 106 */ 107 static QDF_STATUS tgt_ocb_get_tsf_timer(struct wlan_objmgr_psoc * psoc,struct ocb_get_tsf_timer_response * response)108 tgt_ocb_get_tsf_timer(struct wlan_objmgr_psoc *psoc, 109 struct ocb_get_tsf_timer_response *response) 110 { 111 QDF_STATUS status; 112 struct scheduler_msg msg = {0}; 113 struct ocb_rx_event *event; 114 115 event = qdf_mem_malloc(sizeof(*event)); 116 if (!event) 117 return QDF_STATUS_E_NOMEM; 118 119 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); 120 if (QDF_IS_STATUS_ERROR(status)) { 121 ocb_err("Failed to get psoc ref"); 122 goto flush_ref; 123 } 124 event->psoc = psoc; 125 event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 126 response->vdev_id, 127 WLAN_OCB_SB_ID); 128 if (!event->vdev) { 129 ocb_err("Cannot get vdev handle"); 130 status = QDF_STATUS_E_FAILURE; 131 goto flush_ref; 132 } 133 134 event->evt_id = OCB_TSF_TIMER; 135 event->rsp.tsf_timer.vdev_id = response->vdev_id; 136 event->rsp.tsf_timer.timer_high = response->timer_high; 137 event->rsp.tsf_timer.timer_low = response->timer_low; 138 msg.type = OCB_TSF_TIMER; 139 msg.bodyptr = event; 140 msg.callback = ocb_process_evt; 141 msg.flush_callback = wlan_ocb_flush_callback; 142 143 status = scheduler_post_message(QDF_MODULE_ID_OCB, 144 QDF_MODULE_ID_OCB, 145 QDF_MODULE_ID_TARGET_IF, &msg); 146 if (QDF_IS_STATUS_SUCCESS(status)) 147 return QDF_STATUS_SUCCESS; 148 149 ocb_err("failed to send OCB_TSF_TIMER msg"); 150 flush_ref: 151 wlan_ocb_release_rx_event(event); 152 153 return status; 154 } 155 156 /** 157 * tgt_ocb_dcc_ndl_update() - handler for NDL update response 158 * @psoc: psoc handle 159 * @resp: NDL update response 160 * 161 * Return: QDF_STATUS_SUCCESS on success 162 */ 163 static QDF_STATUS tgt_ocb_dcc_ndl_update(struct wlan_objmgr_psoc * psoc,struct ocb_dcc_update_ndl_response * resp)164 tgt_ocb_dcc_ndl_update(struct wlan_objmgr_psoc *psoc, 165 struct ocb_dcc_update_ndl_response *resp) 166 { 167 QDF_STATUS status; 168 struct scheduler_msg msg = {0}; 169 struct ocb_rx_event *event; 170 171 event = qdf_mem_malloc(sizeof(*event)); 172 if (!event) 173 return QDF_STATUS_E_NOMEM; 174 175 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); 176 if (QDF_IS_STATUS_ERROR(status)) { 177 ocb_err("Failed to get psoc ref"); 178 goto flush_ref; 179 } 180 event->psoc = psoc; 181 event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 182 resp->vdev_id, 183 WLAN_OCB_SB_ID); 184 if (!event->vdev) { 185 ocb_err("Cannot get vdev handle"); 186 status = QDF_STATUS_E_FAILURE; 187 goto flush_ref; 188 } 189 190 event->evt_id = OCB_NDL_RESPONSE; 191 qdf_mem_copy(&event->rsp.ndl, resp, sizeof(*resp)); 192 msg.type = OCB_NDL_RESPONSE; 193 msg.bodyptr = event; 194 msg.callback = ocb_process_evt; 195 msg.flush_callback = wlan_ocb_flush_callback; 196 197 status = scheduler_post_message(QDF_MODULE_ID_OCB, 198 QDF_MODULE_ID_OCB, 199 QDF_MODULE_ID_TARGET_IF, &msg); 200 if (QDF_IS_STATUS_SUCCESS(status)) 201 return QDF_STATUS_SUCCESS; 202 203 ocb_err("failed to send OCB_NDL_RESPONSE msg"); 204 flush_ref: 205 wlan_ocb_release_rx_event(event); 206 207 return status; 208 } 209 210 /** 211 * tgt_ocb_dcc_stats_indicate() - handler for DCC stats indication 212 * @psoc: psoc handle 213 * @response: DCC stats 214 * @active: true for active query, false for passive indicate 215 * 216 * Return: QDF_STATUS_SUCCESS on success 217 */ 218 static QDF_STATUS tgt_ocb_dcc_stats_indicate(struct wlan_objmgr_psoc * psoc,struct ocb_dcc_get_stats_response * response,bool active)219 tgt_ocb_dcc_stats_indicate(struct wlan_objmgr_psoc *psoc, 220 struct ocb_dcc_get_stats_response *response, 221 bool active) 222 { 223 QDF_STATUS status; 224 uint8_t *buf; 225 uint32_t size; 226 struct scheduler_msg msg = {0}; 227 struct ocb_rx_event *event; 228 229 size = sizeof(*event) + 230 response->channel_stats_array_len; 231 buf = qdf_mem_malloc(size); 232 if (!buf) 233 return QDF_STATUS_E_NOMEM; 234 235 event = (struct ocb_rx_event *)buf; 236 status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); 237 if (QDF_IS_STATUS_ERROR(status)) { 238 ocb_err("Failed to get psoc ref"); 239 goto flush_ref; 240 } 241 event->psoc = psoc; 242 event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, 243 response->vdev_id, 244 WLAN_OCB_SB_ID); 245 if (!event->vdev) { 246 ocb_err("Cannot get vdev handle"); 247 status = QDF_STATUS_E_FAILURE; 248 goto flush_ref; 249 } 250 251 event->rsp.dcc_stats.channel_stats_array = 252 (uint8_t *)&event->rsp.dcc_stats + 253 sizeof(struct ocb_dcc_get_stats_response); 254 event->rsp.dcc_stats.vdev_id = response->vdev_id; 255 event->rsp.dcc_stats.num_channels = response->num_channels; 256 event->rsp.dcc_stats.channel_stats_array_len = 257 response->channel_stats_array_len; 258 qdf_mem_copy(event->rsp.dcc_stats.channel_stats_array, 259 response->channel_stats_array, 260 response->channel_stats_array_len); 261 ocb_debug("Message type is %s", 262 active ? "Get stats response" : "DCC stats indication"); 263 if (active) 264 msg.type = OCB_DCC_STATS_RESPONSE; 265 else 266 msg.type = OCB_DCC_INDICATION; 267 event->evt_id = msg.type; 268 msg.bodyptr = event; 269 msg.callback = ocb_process_evt; 270 msg.flush_callback = wlan_ocb_flush_callback; 271 272 status = scheduler_post_message(QDF_MODULE_ID_OCB, 273 QDF_MODULE_ID_OCB, 274 QDF_MODULE_ID_TARGET_IF, &msg); 275 if (QDF_IS_STATUS_SUCCESS(status)) 276 return QDF_STATUS_SUCCESS; 277 278 ocb_err("failed to send DCC stats msg(%d)", msg.type); 279 flush_ref: 280 wlan_ocb_release_rx_event(event); 281 282 return status; 283 } 284 tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev * pdev)285 QDF_STATUS tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev *pdev) 286 { 287 struct wlan_objmgr_psoc *psoc; 288 struct wlan_ocb_tx_ops *ocb_ops; 289 QDF_STATUS status = QDF_STATUS_E_FAILURE; 290 291 psoc = wlan_pdev_get_psoc(pdev); 292 if (!psoc) { 293 ocb_err("Null soc handle"); 294 return QDF_STATUS_E_INVAL; 295 } 296 ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev); 297 if (ocb_ops && ocb_ops->ocb_reg_ev_handler) { 298 status = ocb_ops->ocb_reg_ev_handler(psoc, NULL); 299 ocb_debug("register ocb event, status:%d", status); 300 } else { 301 ocb_alert("No ocb objects or ocb_reg_ev_handler"); 302 } 303 304 return status; 305 } 306 tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev * pdev)307 QDF_STATUS tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev *pdev) 308 { 309 struct wlan_objmgr_psoc *psoc; 310 struct wlan_ocb_tx_ops *ocb_ops; 311 QDF_STATUS status; 312 313 psoc = wlan_pdev_get_psoc(pdev); 314 if (!psoc) { 315 ocb_err("Null soc handle"); 316 return QDF_STATUS_E_INVAL; 317 } 318 ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev); 319 if (ocb_ops && ocb_ops->ocb_unreg_ev_handler) { 320 status = ocb_ops->ocb_unreg_ev_handler(psoc, NULL); 321 ocb_debug("unregister ocb event, status:%d", status); 322 } else { 323 ocb_alert("No ocb objects or ocb_unreg_ev_handler"); 324 status = QDF_STATUS_E_FAILURE; 325 } 326 327 return status; 328 } 329 tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops * ocb_rxops)330 QDF_STATUS tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops *ocb_rxops) 331 { 332 ocb_rxops->ocb_set_config_status = tgt_ocb_channel_config_status; 333 ocb_rxops->ocb_tsf_timer = tgt_ocb_get_tsf_timer; 334 ocb_rxops->ocb_dcc_ndl_update = tgt_ocb_dcc_ndl_update; 335 ocb_rxops->ocb_dcc_stats_indicate = tgt_ocb_dcc_stats_indicate; 336 337 return QDF_STATUS_SUCCESS; 338 } 339