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