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: contains core ocb function definitions 22 */ 23 24 #include <qdf_status.h> 25 #include "scheduler_api.h" 26 #include "wlan_objmgr_cmn.h" 27 #include "wlan_objmgr_global_obj.h" 28 #include "wlan_objmgr_psoc_obj.h" 29 #include "wlan_objmgr_pdev_obj.h" 30 #include "wlan_objmgr_vdev_obj.h" 31 #include <cdp_txrx_handle.h> 32 #include <cdp_txrx_cmn.h> 33 #include <cdp_txrx_ocb.h> 34 #include "wlan_ocb_main.h" 35 #include "wlan_ocb_tgt_api.h" 36 #include "target_if_ocb.h" 37 38 /** 39 * ocb_get_cmd_type_str() - parse cmd to string 40 * @cmd_type: ocb cmd type 41 * 42 * This function parse ocb cmd to string. 43 * 44 * Return: command string 45 */ 46 static const char *ocb_get_evt_type_str(enum ocb_southbound_event evt_type) 47 { 48 switch (evt_type) { 49 case OCB_CHANNEL_CONFIG_STATUS: 50 return "OCB channel config status"; 51 case OCB_TSF_TIMER: 52 return "OCB TSF timer"; 53 case OCB_DCC_STATS_RESPONSE: 54 return "OCB DCC get stats response"; 55 case OCB_NDL_RESPONSE: 56 return "OCB NDL indication"; 57 case OCB_DCC_INDICATION: 58 return "OCB DCC stats indication"; 59 default: 60 return "Invalid OCB command"; 61 } 62 } 63 64 /** 65 * ocb_set_chan_info() - Set channel info to dp 66 * @dp_soc: data path soc handle 67 * @dp_pdev: data path pdev handle 68 * @vdev_id: OCB vdev_id 69 * @config: channel config parameters 70 * 71 * Return: QDF_STATUS_SUCCESS on success 72 */ 73 static QDF_STATUS ocb_set_chan_info(void *dp_soc, 74 void *dp_pdev, 75 uint32_t vdev_id, 76 struct ocb_config *config) 77 { 78 struct ol_txrx_ocb_set_chan ocb_set_chan; 79 struct ol_txrx_ocb_chan_info *ocb_channel_info; 80 81 if (!dp_soc || !dp_pdev) { 82 ocb_err("DP global handle is null"); 83 return QDF_STATUS_E_INVAL; 84 } 85 86 ocb_set_chan.ocb_channel_count = config->channel_count; 87 88 /* release old settings */ 89 ocb_channel_info = cdp_get_ocb_chan_info(dp_soc, vdev_id); 90 if (ocb_channel_info) 91 qdf_mem_free(ocb_channel_info); 92 93 if (config->channel_count) { 94 int i, buf_size; 95 96 buf_size = sizeof(*ocb_channel_info) * config->channel_count; 97 ocb_set_chan.ocb_channel_info = qdf_mem_malloc(buf_size); 98 if (!ocb_set_chan.ocb_channel_info) 99 return QDF_STATUS_E_NOMEM; 100 101 ocb_channel_info = ocb_set_chan.ocb_channel_info; 102 for (i = 0; i < config->channel_count; i++) { 103 ocb_channel_info[i].chan_freq = 104 config->channels[i].chan_freq; 105 if (config->channels[i].flags & 106 OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR) 107 ocb_channel_info[i].disable_rx_stats_hdr = 1; 108 } 109 } else { 110 ocb_debug("No channel config to dp"); 111 ocb_set_chan.ocb_channel_info = NULL; 112 } 113 ocb_debug("Sync channel config to dp"); 114 cdp_set_ocb_chan_info(dp_soc, vdev_id, ocb_set_chan); 115 116 return QDF_STATUS_SUCCESS; 117 } 118 119 /** 120 * ocb_channel_config_status() - Process set channel config response 121 * @evt: response event 122 * 123 * Return: QDF_STATUS_SUCCESS on success 124 */ 125 static QDF_STATUS ocb_channel_config_status(struct ocb_rx_event *evt) 126 { 127 QDF_STATUS status; 128 uint32_t vdev_id; 129 struct ocb_rx_event *event; 130 struct wlan_objmgr_psoc *psoc; 131 struct wlan_objmgr_pdev *pdev; 132 struct ocb_pdev_obj *ocb_obj; 133 struct ocb_callbacks *cbs; 134 struct ocb_set_config_response config_rsp; 135 136 if (!evt) { 137 ocb_err("Event buffer is NULL"); 138 return QDF_STATUS_E_FAILURE; 139 } 140 event = evt; 141 psoc = event->psoc; 142 pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_OCB_SB_ID); 143 if (!pdev) { 144 ocb_alert("Pdev is NULL"); 145 return QDF_STATUS_E_FAILURE; 146 } 147 148 ocb_obj = wlan_get_pdev_ocb_obj(pdev); 149 if (!ocb_obj) { 150 ocb_err("Pdev object is NULL"); 151 status = QDF_STATUS_E_INVAL; 152 goto exit; 153 } 154 155 cbs = &ocb_obj->ocb_cbs; 156 if (ocb_obj->channel_config) { 157 vdev_id = ocb_obj->channel_config->vdev_id; 158 config_rsp = event->rsp.channel_cfg_rsp; 159 160 /* Sync channel status to data path */ 161 if (config_rsp.status == OCB_CHANNEL_CONFIG_SUCCESS) 162 ocb_set_chan_info(ocb_obj->dp_soc, 163 ocb_obj->pdev, 164 vdev_id, 165 ocb_obj->channel_config); 166 qdf_mem_free(ocb_obj->channel_config); 167 ocb_obj->channel_config = NULL; 168 } else { 169 ocb_err("Failed to sync channel info to DP"); 170 config_rsp.status = OCB_CHANNEL_CONFIG_FAIL; 171 } 172 173 if (cbs->ocb_set_config_callback) { 174 cbs->ocb_set_config_callback(cbs->ocb_set_config_context, 175 &config_rsp); 176 status = QDF_STATUS_SUCCESS; 177 } else { 178 ocb_err("ocb_set_config_resp_cb is NULL"); 179 status = QDF_STATUS_E_INVAL; 180 } 181 exit: 182 wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID); 183 184 return status; 185 } 186 187 /** 188 * ocb_tsf_timer() - Process get TSF timer response 189 * @evt: response event 190 * 191 * Return: QDF_STATUS_SUCCESS on success 192 */ 193 static QDF_STATUS ocb_tsf_timer(struct ocb_rx_event *evt) 194 { 195 QDF_STATUS status; 196 struct ocb_rx_event *event; 197 struct wlan_objmgr_vdev *vdev; 198 struct wlan_objmgr_pdev *pdev; 199 struct ocb_callbacks *cbs; 200 struct ocb_get_tsf_timer_response *tsf_timer; 201 202 if (!evt) { 203 ocb_err("Event buffer is NULL"); 204 return QDF_STATUS_E_FAILURE; 205 } 206 event = evt; 207 vdev = event->vdev; 208 pdev = wlan_vdev_get_pdev(vdev); 209 cbs = wlan_ocb_get_callbacks(pdev); 210 tsf_timer = &event->rsp.tsf_timer; 211 ocb_debug("TSF timer low=%d, high=%d", 212 tsf_timer->timer_low, tsf_timer->timer_high); 213 if (cbs && cbs->ocb_get_tsf_timer_callback) { 214 ocb_debug("send TSF timer"); 215 cbs->ocb_get_tsf_timer_callback(cbs->ocb_get_tsf_timer_context, 216 tsf_timer); 217 status = QDF_STATUS_SUCCESS; 218 } else { 219 ocb_err("ocb_get_tsf_timer_cb is NULL"); 220 status = QDF_STATUS_E_FAILURE; 221 } 222 223 return status; 224 } 225 226 /** 227 * ocb_dcc_stats_response() - Process get DCC stats response 228 * @evt: response event 229 * 230 * Return: QDF_STATUS_SUCCESS on success 231 */ 232 static QDF_STATUS ocb_dcc_stats_response(struct ocb_rx_event *evt) 233 { 234 QDF_STATUS status; 235 struct ocb_rx_event *event; 236 struct wlan_objmgr_vdev *vdev; 237 struct wlan_objmgr_pdev *pdev; 238 struct ocb_callbacks *cbs; 239 struct ocb_dcc_get_stats_response *dcc_stats; 240 241 if (!evt) { 242 ocb_err("Event buffer is NULL"); 243 return QDF_STATUS_E_FAILURE; 244 } 245 246 event = evt; 247 vdev = event->vdev; 248 pdev = wlan_vdev_get_pdev(vdev); 249 cbs = wlan_ocb_get_callbacks(pdev); 250 dcc_stats = &event->rsp.dcc_stats; 251 if (cbs && cbs->ocb_dcc_get_stats_callback) { 252 ocb_debug("send DCC stats"); 253 cbs->ocb_dcc_get_stats_callback(cbs->ocb_dcc_get_stats_context, 254 dcc_stats); 255 status = QDF_STATUS_SUCCESS; 256 } else { 257 ocb_err("dcc_get_stats_cb is NULL"); 258 status = QDF_STATUS_E_FAILURE; 259 } 260 261 return status; 262 } 263 264 /** 265 * ocb_ndl_response() - Process NDL update response 266 * @evt: response event 267 * 268 * Return: QDF_STATUS_SUCCESS on success 269 */ 270 static QDF_STATUS ocb_ndl_response(struct ocb_rx_event *evt) 271 { 272 QDF_STATUS status; 273 struct ocb_rx_event *event; 274 struct wlan_objmgr_vdev *vdev; 275 struct wlan_objmgr_pdev *pdev; 276 struct ocb_callbacks *cbs; 277 struct ocb_dcc_update_ndl_response *ndl; 278 279 if (!evt) { 280 ocb_err("Event buffer is NULL"); 281 return QDF_STATUS_E_FAILURE; 282 } 283 event = evt; 284 vdev = event->vdev; 285 pdev = wlan_vdev_get_pdev(vdev); 286 cbs = wlan_ocb_get_callbacks(pdev); 287 ndl = &event->rsp.ndl; 288 if (cbs && cbs->ocb_dcc_update_ndl_callback) { 289 ocb_debug("NDL update response"); 290 cbs->ocb_dcc_update_ndl_callback( 291 cbs->ocb_dcc_update_ndl_context, ndl); 292 status = QDF_STATUS_SUCCESS; 293 } else { 294 ocb_err("dcc_update_ndl is NULL"); 295 status = QDF_STATUS_E_FAILURE; 296 } 297 298 return status; 299 } 300 301 /** 302 * ocb_dcc_indication() - Process DCC stats indication 303 * @evt: response event 304 * 305 * Return: QDF_STATUS_SUCCESS on success 306 */ 307 static QDF_STATUS ocb_dcc_indication(struct ocb_rx_event *evt) 308 { 309 QDF_STATUS status; 310 struct ocb_rx_event *event; 311 struct wlan_objmgr_vdev *vdev; 312 struct ocb_callbacks *cbs; 313 struct wlan_objmgr_pdev *pdev; 314 struct ocb_dcc_get_stats_response *dcc_stats; 315 316 if (!evt) { 317 ocb_err("Event buffer is NULL"); 318 return QDF_STATUS_E_FAILURE; 319 } 320 321 event = evt; 322 vdev = event->vdev; 323 pdev = wlan_vdev_get_pdev(vdev); 324 cbs = wlan_ocb_get_callbacks(pdev); 325 dcc_stats = &event->rsp.dcc_stats; 326 if (cbs && cbs->ocb_dcc_stats_event_callback) { 327 ocb_debug("DCC stats indication"); 328 cbs->ocb_dcc_stats_event_callback( 329 cbs->ocb_dcc_stats_event_context, dcc_stats); 330 status = QDF_STATUS_SUCCESS; 331 } else { 332 ocb_err("dcc_get_stats_cb is NULL"); 333 status = QDF_STATUS_E_FAILURE; 334 } 335 336 return status; 337 } 338 339 /** 340 * ocb_flush_start_msg() - Flush ocb start message 341 * @msg: OCB start vdev message 342 * 343 * Return: QDF_STATUS_SUCCESS on success. 344 */ 345 static QDF_STATUS ocb_flush_start_msg(struct scheduler_msg *msg) 346 { 347 struct ocb_pdev_obj *ocb_obj; 348 349 if (!msg) { 350 ocb_err("Null point for OCB message"); 351 return QDF_STATUS_E_INVAL; 352 } 353 354 ocb_obj = msg->bodyptr; 355 if (ocb_obj && ocb_obj->channel_config) { 356 ocb_info("release the backed config parameters"); 357 qdf_mem_free(ocb_obj->channel_config); 358 ocb_obj->channel_config = NULL; 359 } 360 361 return QDF_STATUS_SUCCESS; 362 } 363 364 /** 365 * ocb_process_start_vdev_msg() - Handler for OCB vdev start message 366 * @msg: OCB start vdev message 367 * 368 * Return: QDF_STATUS_SUCCESS on success. 369 */ 370 static QDF_STATUS ocb_process_start_vdev_msg(struct scheduler_msg *msg) 371 { 372 QDF_STATUS status; 373 struct ocb_config *config; 374 struct ocb_pdev_obj *ocb_obj; 375 struct ocb_callbacks *ocb_cbs; 376 struct wlan_objmgr_vdev *vdev; 377 378 if (!msg || !msg->bodyptr) { 379 ocb_err("invalid message"); 380 return QDF_STATUS_E_INVAL; 381 } 382 383 ocb_obj = msg->bodyptr; 384 ocb_cbs = &ocb_obj->ocb_cbs; 385 if (!ocb_cbs->start_ocb_vdev) { 386 ocb_err("No callback to start ocb vdev"); 387 return QDF_STATUS_E_FAILURE; 388 } 389 390 config = ocb_obj->channel_config; 391 if (!config) { 392 ocb_err("NULL config parameters"); 393 return QDF_STATUS_E_INVAL; 394 } 395 396 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ocb_obj->pdev, 397 config->vdev_id, 398 WLAN_OCB_SB_ID); 399 if (!vdev) { 400 ocb_err("Cannot get vdev"); 401 return QDF_STATUS_E_FAILURE; 402 } 403 404 ocb_debug("Start to send OCB vdev start cmd"); 405 status = ocb_cbs->start_ocb_vdev(config); 406 wlan_objmgr_vdev_release_ref(vdev, WLAN_OCB_SB_ID); 407 if (QDF_IS_STATUS_ERROR(status)) { 408 ocb_err("Failed to start OCB vdev"); 409 return QDF_STATUS_E_FAILURE; 410 } 411 412 return QDF_STATUS_SUCCESS; 413 } 414 415 QDF_STATUS ocb_vdev_start(struct ocb_pdev_obj *ocb_obj) 416 { 417 QDF_STATUS status; 418 struct scheduler_msg msg = {0}; 419 420 msg.bodyptr = ocb_obj; 421 msg.callback = ocb_process_start_vdev_msg; 422 msg.flush_callback = ocb_flush_start_msg; 423 status = scheduler_post_message(QDF_MODULE_ID_OCB, 424 QDF_MODULE_ID_OCB, 425 QDF_MODULE_ID_TARGET_IF, &msg); 426 427 return status; 428 } 429 430 QDF_STATUS ocb_process_evt(struct scheduler_msg *msg) 431 { 432 QDF_STATUS status; 433 struct ocb_rx_event *event; 434 435 ocb_debug("msg type %d, %s", msg->type, 436 ocb_get_evt_type_str(msg->type)); 437 438 if (!(msg->bodyptr)) { 439 ocb_err("Invalid message body"); 440 return QDF_STATUS_E_INVAL; 441 } 442 event = msg->bodyptr; 443 switch (msg->type) { 444 case OCB_CHANNEL_CONFIG_STATUS: 445 status = ocb_channel_config_status(event); 446 break; 447 case OCB_TSF_TIMER: 448 status = ocb_tsf_timer(event); 449 break; 450 case OCB_DCC_STATS_RESPONSE: 451 status = ocb_dcc_stats_response(event); 452 break; 453 case OCB_NDL_RESPONSE: 454 status = ocb_ndl_response(event); 455 break; 456 case OCB_DCC_INDICATION: 457 status = ocb_dcc_indication(event); 458 break; 459 default: 460 status = QDF_STATUS_E_INVAL; 461 break; 462 } 463 464 wlan_ocb_release_rx_event(event); 465 msg->bodyptr = NULL; 466 467 return status; 468 } 469 470 struct ocb_config *ocb_copy_config(struct ocb_config *src) 471 { 472 struct ocb_config *dst; 473 uint32_t length; 474 uint8_t *cursor; 475 476 length = sizeof(*src) + 477 src->channel_count * sizeof(*src->channels) + 478 src->schedule_size * sizeof(*src->schedule) + 479 src->dcc_ndl_chan_list_len + 480 src->dcc_ndl_active_state_list_len; 481 482 dst = qdf_mem_malloc(length); 483 if (!dst) 484 return NULL; 485 486 *dst = *src; 487 488 cursor = (uint8_t *)dst; 489 cursor += sizeof(*dst); 490 dst->channels = (struct ocb_config_chan *)cursor; 491 cursor += src->channel_count * sizeof(*dst->channels); 492 qdf_mem_copy(dst->channels, src->channels, 493 src->channel_count * sizeof(*dst->channels)); 494 dst->schedule = (struct ocb_config_schdl *)cursor; 495 cursor += src->schedule_size * sizeof(*dst->schedule); 496 qdf_mem_copy(dst->schedule, src->schedule, 497 src->schedule_size * sizeof(*dst->schedule)); 498 dst->dcc_ndl_chan_list = cursor; 499 cursor += src->dcc_ndl_chan_list_len; 500 qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list, 501 src->dcc_ndl_chan_list_len); 502 dst->dcc_ndl_active_state_list = cursor; 503 cursor += src->dcc_ndl_active_state_list_len; 504 qdf_mem_copy(dst->dcc_ndl_active_state_list, 505 src->dcc_ndl_active_state_list, 506 src->dcc_ndl_active_state_list_len); 507 508 return dst; 509 } 510 511 QDF_STATUS ocb_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, 512 void *arg_list) 513 { 514 QDF_STATUS status; 515 struct ocb_pdev_obj *ocb_obj; 516 517 ocb_notice("ocb pdev created"); 518 ocb_obj = qdf_mem_malloc(sizeof(*ocb_obj)); 519 if (!ocb_obj) 520 return QDF_STATUS_E_FAILURE; 521 522 status = wlan_objmgr_pdev_component_obj_attach(pdev, 523 WLAN_UMAC_COMP_OCB, 524 (void *)ocb_obj, 525 QDF_STATUS_SUCCESS); 526 if (QDF_IS_STATUS_ERROR(status)) { 527 ocb_err("Failed to attach pdev ocb component"); 528 qdf_mem_free(ocb_obj); 529 return status; 530 } 531 ocb_obj->pdev = pdev; 532 533 /* register OCB tx/rx ops */ 534 tgt_ocb_register_rx_ops(&ocb_obj->ocb_rxops); 535 target_if_ocb_register_tx_ops(&ocb_obj->ocb_txops); 536 ocb_notice("ocb pdev attached"); 537 538 return status; 539 } 540 541 QDF_STATUS ocb_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, 542 void *arg_list) 543 { 544 QDF_STATUS status; 545 struct ocb_pdev_obj *ocb_obj; 546 547 ocb_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, 548 WLAN_UMAC_COMP_OCB); 549 if (!ocb_obj) { 550 ocb_err("Failed to get ocb pdev object"); 551 return QDF_STATUS_E_FAILURE; 552 } 553 554 status = wlan_objmgr_pdev_component_obj_detach(pdev, 555 WLAN_UMAC_COMP_OCB, 556 ocb_obj); 557 if (QDF_IS_STATUS_ERROR(status)) 558 ocb_err("Failed to detatch ocb pdev object"); 559 560 qdf_mem_free(ocb_obj); 561 562 return QDF_STATUS_SUCCESS; 563 } 564