1 /* 2 * Copyright (c) 2013-2018 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: wma_ocb.c 21 * 22 * WLAN Host Device Driver 802.11p OCB implementation 23 */ 24 25 #include "wma_ocb.h" 26 #include "wmi_unified_api.h" 27 #include "cds_utils.h" 28 #include "cds_api.h" 29 #include <cdp_txrx_ocb.h> 30 #include <cdp_txrx_handle.h> 31 #include "wlan_ocb_ucfg_api.h" 32 33 /** 34 * wma_ocb_resp() - send the OCB set config response via callback 35 * @wma_handle: pointer to the WMA handle 36 * @status: status of the set config command 37 */ 38 int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status) 39 { 40 QDF_STATUS qdf_status; 41 struct sir_ocb_set_config_response *resp; 42 struct scheduler_msg msg = {0}; 43 struct sir_ocb_config *req = wma_handle->ocb_config_req; 44 void *vdev = (req ? 45 wma_handle->interfaces[req->session_id].handle : NULL); 46 struct ol_txrx_ocb_set_chan ocb_set_chan; 47 void *soc = cds_get_context(QDF_MODULE_ID_SOC); 48 49 /* 50 * If the command was successful, save the channel information in the 51 * vdev. 52 */ 53 if (status == QDF_STATUS_SUCCESS && vdev && req) { 54 ocb_set_chan.ocb_channel_info = cdp_get_ocb_chan_info(soc, 55 (struct cdp_vdev *)vdev); 56 if (ocb_set_chan.ocb_channel_info) 57 qdf_mem_free(ocb_set_chan.ocb_channel_info); 58 ocb_set_chan.ocb_channel_count = 59 req->channel_count; 60 if (req->channel_count) { 61 int i; 62 int buf_size = sizeof(*ocb_set_chan.ocb_channel_info) * 63 req->channel_count; 64 ocb_set_chan.ocb_channel_info = 65 qdf_mem_malloc(buf_size); 66 if (!ocb_set_chan.ocb_channel_info) 67 return -ENOMEM; 68 qdf_mem_zero(ocb_set_chan.ocb_channel_info, buf_size); 69 for (i = 0; i < req->channel_count; i++) { 70 ocb_set_chan.ocb_channel_info[i].chan_freq = 71 req->channels[i].chan_freq; 72 if (req->channels[i].flags & 73 OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR) 74 ocb_set_chan.ocb_channel_info[i]. 75 disable_rx_stats_hdr = 1; 76 } 77 } else { 78 ocb_set_chan.ocb_channel_info = 0; 79 ocb_set_chan.ocb_channel_count = 0; 80 } 81 cdp_set_ocb_chan_info(soc, 82 (struct cdp_vdev *)vdev, 83 ocb_set_chan); 84 } 85 86 /* Free the configuration that was saved in wma_ocb_set_config. */ 87 qdf_mem_free(wma_handle->ocb_config_req); 88 wma_handle->ocb_config_req = NULL; 89 90 resp = qdf_mem_malloc(sizeof(*resp)); 91 if (!resp) 92 return -ENOMEM; 93 94 resp->status = status; 95 96 msg.type = eWNI_SME_OCB_SET_CONFIG_RSP; 97 msg.bodyptr = resp; 98 99 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg); 100 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 101 WMA_LOGE(FL("Fail to post msg to SME")); 102 qdf_mem_free(resp); 103 return -EINVAL; 104 } 105 106 return 0; 107 } 108 109 /** 110 * copy_sir_ocb_config() - deep copy of an OCB config struct 111 * @src: pointer to the source struct 112 * 113 * Return: pointer to the copied struct 114 */ 115 static struct sir_ocb_config *copy_sir_ocb_config(struct sir_ocb_config *src) 116 { 117 struct sir_ocb_config *dst; 118 uint32_t length; 119 void *cursor; 120 121 length = sizeof(*src) + 122 src->channel_count * sizeof(*src->channels) + 123 src->schedule_size * sizeof(*src->schedule) + 124 src->dcc_ndl_chan_list_len + 125 src->dcc_ndl_active_state_list_len; 126 127 dst = qdf_mem_malloc(length); 128 if (!dst) 129 return NULL; 130 131 *dst = *src; 132 133 cursor = dst; 134 cursor += sizeof(*dst); 135 dst->channels = cursor; 136 cursor += src->channel_count * sizeof(*dst->channels); 137 qdf_mem_copy(dst->channels, src->channels, 138 src->channel_count * sizeof(*dst->channels)); 139 dst->schedule = cursor; 140 cursor += src->schedule_size * sizeof(*dst->schedule); 141 qdf_mem_copy(dst->schedule, src->schedule, 142 src->schedule_size * sizeof(*dst->schedule)); 143 dst->dcc_ndl_chan_list = cursor; 144 cursor += src->dcc_ndl_chan_list_len; 145 qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list, 146 src->dcc_ndl_chan_list_len); 147 dst->dcc_ndl_active_state_list = cursor; 148 cursor += src->dcc_ndl_active_state_list_len; 149 qdf_mem_copy(dst->dcc_ndl_active_state_list, 150 src->dcc_ndl_active_state_list, 151 src->dcc_ndl_active_state_list_len); 152 return dst; 153 } 154 155 /** 156 * wma_ocb_set_config_req() - send the OCB config request 157 * @wma_handle: pointer to the WMA handle 158 * @config_req: the configuration to be set. 159 */ 160 int wma_ocb_set_config_req(tp_wma_handle wma_handle, 161 struct sir_ocb_config *config_req) 162 { 163 struct wma_target_req *msg; 164 struct wma_vdev_start_req req; 165 QDF_STATUS status = QDF_STATUS_SUCCESS; 166 167 /* if vdev is not yet up, send vdev start request and wait for response. 168 * OCB set_config request should be sent on receiving 169 * vdev start response message 170 */ 171 if (!wma_is_vdev_up(config_req->session_id)) { 172 qdf_mem_zero(&req, sizeof(req)); 173 /* Enqueue OCB Set Schedule request message */ 174 msg = wma_fill_vdev_req(wma_handle, config_req->session_id, 175 WMA_OCB_SET_CONFIG_CMD, 176 WMA_TARGET_REQ_TYPE_VDEV_START, 177 (void *)config_req, 1000); 178 if (!msg) { 179 WMA_LOGE(FL("Failed to fill vdev req %d"), req.vdev_id); 180 status = QDF_STATUS_E_NOMEM; 181 return status; 182 } 183 req.chan = cds_freq_to_chan(config_req->channels[0].chan_freq); 184 req.vdev_id = msg->vdev_id; 185 if (cds_chan_to_band(req.chan) == CDS_BAND_2GHZ) 186 req.dot11_mode = WNI_CFG_DOT11_MODE_11G; 187 else 188 req.dot11_mode = WNI_CFG_DOT11_MODE_11A; 189 190 if (wma_handle->ocb_config_req) 191 qdf_mem_free(wma_handle->ocb_config_req); 192 wma_handle->ocb_config_req = copy_sir_ocb_config(config_req); 193 req.preferred_rx_streams = 2; 194 req.preferred_tx_streams = 2; 195 196 status = wma_vdev_start(wma_handle, &req, false); 197 if (status != QDF_STATUS_SUCCESS) { 198 wma_remove_vdev_req(wma_handle, req.vdev_id, 199 WMA_TARGET_REQ_TYPE_VDEV_START); 200 WMA_LOGE(FL("vdev_start failed, status = %d"), status); 201 } 202 return 0; 203 } else { 204 return wma_ocb_set_config(wma_handle, config_req); 205 } 206 } 207 208 int wma_ocb_start_resp_ind_cont(tp_wma_handle wma_handle) 209 { 210 QDF_STATUS qdf_status = 0; 211 212 if (!wma_handle->ocb_config_req) { 213 WMA_LOGE(FL("The request could not be found")); 214 return QDF_STATUS_E_EMPTY; 215 } 216 217 qdf_status = wma_ocb_set_config(wma_handle, wma_handle->ocb_config_req); 218 return qdf_status; 219 } 220 221 static WLAN_PHY_MODE wma_ocb_freq_to_mode(uint32_t freq) 222 { 223 if (cds_chan_to_band(cds_freq_to_chan(freq)) == CDS_BAND_2GHZ) 224 return MODE_11G; 225 else 226 return MODE_11A; 227 } 228 229 /** 230 * wma_send_ocb_set_config() - send the OCB config to the FW 231 * @wma_handle: pointer to the WMA handle 232 * @config: the OCB configuration 233 * 234 * Return: 0 on success 235 */ 236 int wma_ocb_set_config(tp_wma_handle wma_handle, struct sir_ocb_config *config) 237 { 238 int32_t ret, i; 239 uint32_t *ch_mhz; 240 struct ocb_config tconfig = {0}; 241 242 tconfig.vdev_id = config->session_id; 243 tconfig.channel_count = config->channel_count; 244 tconfig.schedule_size = config->schedule_size; 245 tconfig.flags = config->flags; 246 tconfig.channels = (struct ocb_config_chan *)config->channels; 247 tconfig.schedule = (struct ocb_config_schdl *)config->schedule; 248 tconfig.dcc_ndl_chan_list_len = config->dcc_ndl_chan_list_len; 249 tconfig.dcc_ndl_chan_list = config->dcc_ndl_chan_list; 250 tconfig.dcc_ndl_active_state_list_len = 251 config->dcc_ndl_active_state_list_len; 252 tconfig.dcc_ndl_active_state_list = config->dcc_ndl_active_state_list; 253 ch_mhz = qdf_mem_malloc(sizeof(uint32_t)*config->channel_count); 254 if (ch_mhz == NULL) { 255 WMA_LOGE(FL("Memory allocation failed")); 256 return -ENOMEM; 257 } 258 259 for (i = 0; i < config->channel_count; i++) 260 ch_mhz[i] = wma_ocb_freq_to_mode(config->channels[i].chan_freq); 261 262 /* 263 * Save the configuration so that it can be used in 264 * wma_ocb_set_config_event_handler. 265 */ 266 if (wma_handle->ocb_config_req != config) { 267 if (wma_handle->ocb_config_req) 268 qdf_mem_free(wma_handle->ocb_config_req); 269 wma_handle->ocb_config_req = copy_sir_ocb_config(config); 270 } 271 272 ret = wmi_unified_ocb_set_config(wma_handle->wmi_handle, &tconfig); 273 if (ret != EOK) { 274 if (wma_handle->ocb_config_req) { 275 qdf_mem_free(wma_handle->ocb_config_req); 276 wma_handle->ocb_config_req = NULL; 277 } 278 qdf_mem_free(ch_mhz); 279 WMA_LOGE("Failed to set OCB config"); 280 return -EIO; 281 } 282 qdf_mem_free(ch_mhz); 283 284 return 0; 285 } 286 287 /** 288 * wma_ocb_set_config_event_handler() - Response event for the set config cmd 289 * @handle: the WMA handle 290 * @event_buf: buffer with the event parameters 291 * @len: length of the buffer 292 * 293 * Return: 0 on success 294 */ 295 int wma_ocb_set_config_event_handler(void *handle, uint8_t *event_buf, 296 uint32_t len) 297 { 298 WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *param_tlvs; 299 wmi_ocb_set_config_resp_event_fixed_param *fix_param; 300 301 param_tlvs = (WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *)event_buf; 302 fix_param = param_tlvs->fixed_param; 303 return wma_ocb_set_config_resp(handle, fix_param->status); 304 }; 305 306 /** 307 * wma_ocb_set_utc_time() - send the UTC time to the firmware 308 * @wma_handle: pointer to the WMA handle 309 * @utc: pointer to the UTC time struct 310 * 311 * Return: 0 on succes 312 */ 313 int wma_ocb_set_utc_time(tp_wma_handle wma_handle, struct sir_ocb_utc *utc) 314 { 315 int32_t ret; 316 struct ocb_utc_param cmd = {0}; 317 318 cmd.vdev_id = utc->vdev_id; 319 qdf_mem_copy(&cmd.utc_time, &utc->utc_time, WMI_SIZE_UTC_TIME); 320 qdf_mem_copy(&cmd.time_error, &utc->time_error, 321 WMI_SIZE_UTC_TIME_ERROR); 322 ret = wmi_unified_ocb_set_utc_time_cmd(wma_handle->wmi_handle, &cmd); 323 if (ret != EOK) { 324 WMA_LOGE(FL("Failed to set OCB UTC time")); 325 return -EIO; 326 } 327 328 return 0; 329 } 330 331 /** 332 * wma_ocb_start_timing_advert() - start sending the timing advertisement 333 * frames on a channel 334 * @wma_handle: pointer to the WMA handle 335 * @timing_advert: pointer to the timing advertisement struct 336 * 337 * Return: 0 on succes 338 */ 339 int wma_ocb_start_timing_advert(tp_wma_handle wma_handle, 340 struct sir_ocb_timing_advert *timing_advert) 341 { 342 int32_t ret; 343 struct ocb_timing_advert_param cmd = {0}; 344 345 cmd.vdev_id = timing_advert->vdev_id; 346 cmd.repeat_rate = timing_advert->repeat_rate; 347 cmd.chan_freq = timing_advert->chan_freq; 348 cmd.timestamp_offset = timing_advert->timestamp_offset; 349 cmd.time_value_offset = timing_advert->time_value_offset; 350 cmd.template_length = timing_advert->template_length; 351 cmd.template_value = (uint8_t *)timing_advert->template_value; 352 353 ret = wmi_unified_ocb_start_timing_advert(wma_handle->wmi_handle, 354 &cmd); 355 if (ret != EOK) { 356 WMA_LOGE(FL("Failed to start OCB timing advert")); 357 return -EIO; 358 } 359 360 return 0; 361 } 362 363 /** 364 * wma_ocb_stop_timing_advert() - stop sending the timing advertisement frames 365 * on a channel 366 * @wma_handle: pointer to the WMA handle 367 * @timing_advert: pointer to the timing advertisement struct 368 * 369 * Return: 0 on succes 370 */ 371 int wma_ocb_stop_timing_advert(tp_wma_handle wma_handle, 372 struct sir_ocb_timing_advert *timing_advert) 373 { 374 int32_t ret; 375 struct ocb_timing_advert_param cmd = {0}; 376 377 cmd.vdev_id = timing_advert->vdev_id; 378 cmd.chan_freq = timing_advert->chan_freq; 379 ret = wmi_unified_ocb_stop_timing_advert(wma_handle->wmi_handle, 380 &cmd); 381 if (ret != EOK) { 382 WMA_LOGE(FL("Failed to stop OCB timing advert")); 383 return -EIO; 384 } 385 386 return 0; 387 } 388 389 /** 390 * wma_ocb_get_tsf_timer() - stop sending the timing advertisement frames on a 391 * channel 392 * @wma_handle: pointer to the WMA handle 393 * @request: pointer to the request 394 * 395 * Return: 0 on succes 396 */ 397 int wma_ocb_get_tsf_timer(tp_wma_handle wma_handle, 398 struct sir_ocb_get_tsf_timer *request) 399 { 400 QDF_STATUS ret; 401 402 /* Send the WMI command */ 403 ret = wmi_unified_ocb_get_tsf_timer(wma_handle->wmi_handle, 404 (struct ocb_get_tsf_timer_param *)request); 405 /* If there is an error, set the completion event */ 406 if (ret != EOK) { 407 WMA_LOGE(FL("Failed to send WMI message: %d"), ret); 408 return -EIO; 409 } 410 return 0; 411 } 412 413 /** 414 * wma_ocb_get_tsf_timer_resp_event_handler() - Event for the get TSF timer cmd 415 * @handle: the WMA handle 416 * @event_buf: buffer with the event parameters 417 * @len: length of the buffer 418 * 419 * Return: 0 on success 420 */ 421 static int wma_ocb_get_tsf_timer_resp_event_handler(void *handle, 422 uint8_t *event_buf, 423 uint32_t len) 424 { 425 QDF_STATUS qdf_status; 426 struct sir_ocb_get_tsf_timer_response *response; 427 WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *param_tlvs; 428 wmi_ocb_get_tsf_timer_resp_event_fixed_param *fix_param; 429 struct scheduler_msg msg = {0}; 430 431 param_tlvs = (WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *)event_buf; 432 fix_param = param_tlvs->fixed_param; 433 434 /* Allocate and populate the response */ 435 response = qdf_mem_malloc(sizeof(*response)); 436 if (response == NULL) 437 return -ENOMEM; 438 response->vdev_id = fix_param->vdev_id; 439 response->timer_high = fix_param->tsf_timer_high; 440 response->timer_low = fix_param->tsf_timer_low; 441 442 msg.type = eWNI_SME_OCB_GET_TSF_TIMER_RSP; 443 msg.bodyptr = response; 444 445 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg); 446 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 447 WMA_LOGE(FL("Failed to post msg to SME")); 448 qdf_mem_free(response); 449 return -EINVAL; 450 } 451 452 return 0; 453 } 454 455 /** 456 * wma_dcc_get_stats() - get the DCC channel stats 457 * @wma_handle: pointer to the WMA handle 458 * @get_stats_param: pointer to the dcc stats 459 * 460 * Return: 0 on succes 461 */ 462 int wma_dcc_get_stats(tp_wma_handle wma_handle, 463 struct sir_dcc_get_stats *get_stats_param) 464 { 465 int32_t ret; 466 struct ocb_dcc_get_stats_param cmd = {0}; 467 468 cmd.vdev_id = get_stats_param->vdev_id; 469 cmd.channel_count = get_stats_param->channel_count; 470 cmd.request_array_len = get_stats_param->request_array_len; 471 cmd.request_array = get_stats_param->request_array; 472 473 /* Send the WMI command */ 474 ret = wmi_unified_dcc_get_stats_cmd(wma_handle->wmi_handle, &cmd); 475 476 if (ret != EOK) { 477 WMA_LOGE(FL("Failed to send WMI message: %d"), ret); 478 return -EIO; 479 } 480 481 return 0; 482 } 483 484 /** 485 * wma_dcc_get_stats_resp_event_handler() - Response event for the get stats cmd 486 * @handle: the WMA handle 487 * @event_buf: buffer with the event parameters 488 * @len: length of the buffer 489 * 490 * Return: 0 on success 491 */ 492 static int wma_dcc_get_stats_resp_event_handler(void *handle, 493 uint8_t *event_buf, 494 uint32_t len) 495 { 496 QDF_STATUS qdf_status; 497 struct sir_dcc_get_stats_response *response; 498 WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *param_tlvs; 499 wmi_dcc_get_stats_resp_event_fixed_param *fix_param; 500 struct scheduler_msg msg = {0}; 501 502 param_tlvs = (WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *)event_buf; 503 fix_param = param_tlvs->fixed_param; 504 505 /* Allocate and populate the response */ 506 if (fix_param->num_channels > ((WMI_SVC_MSG_MAX_SIZE - 507 sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel)) || 508 fix_param->num_channels > param_tlvs->num_stats_per_channel_list) { 509 WMA_LOGE("%s: too many channels:%d, param_tlvs->num_stats_per_channel_list:%d", 510 __func__, fix_param->num_channels, 511 param_tlvs->num_stats_per_channel_list); 512 return -EINVAL; 513 } 514 response = qdf_mem_malloc(sizeof(*response) + fix_param->num_channels * 515 sizeof(wmi_dcc_ndl_stats_per_channel)); 516 if (response == NULL) 517 return -ENOMEM; 518 519 response->vdev_id = fix_param->vdev_id; 520 response->num_channels = fix_param->num_channels; 521 response->channel_stats_array_len = 522 fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel); 523 response->channel_stats_array = ((void *)response) + sizeof(*response); 524 qdf_mem_copy(response->channel_stats_array, 525 param_tlvs->stats_per_channel_list, 526 response->channel_stats_array_len); 527 528 msg.type = eWNI_SME_DCC_GET_STATS_RSP; 529 msg.bodyptr = response; 530 531 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg); 532 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 533 WMA_LOGE(FL("Failed to post msg to SME")); 534 qdf_mem_free(response); 535 return -EINVAL; 536 } 537 538 return 0; 539 } 540 541 /** 542 * wma_dcc_clear_stats() - command to clear the DCC stats 543 * @wma_handle: pointer to the WMA handle 544 * @clear_stats_param: parameters to the command 545 * 546 * Return: 0 on succes 547 */ 548 int wma_dcc_clear_stats(tp_wma_handle wma_handle, 549 struct sir_dcc_clear_stats *clear_stats_param) 550 { 551 int32_t ret; 552 553 /* Send the WMI command */ 554 ret = wmi_unified_dcc_clear_stats(wma_handle->wmi_handle, 555 (struct ocb_dcc_clear_stats_param *)clear_stats_param); 556 if (ret != EOK) { 557 WMA_LOGE(FL("Failed to send the WMI command")); 558 return -EIO; 559 } 560 561 return 0; 562 } 563 564 /** 565 * wma_dcc_update_ndl() - command to update the NDL data 566 * @wma_handle: pointer to the WMA handle 567 * @update_ndl_param: pointer to the request parameters 568 * 569 * Return: 0 on success 570 */ 571 int wma_dcc_update_ndl(tp_wma_handle wma_handle, 572 struct sir_dcc_update_ndl *update_ndl_param) 573 { 574 QDF_STATUS qdf_status; 575 struct ocb_dcc_update_ndl_param *cmd; 576 577 cmd = (struct ocb_dcc_update_ndl_param *) update_ndl_param; 578 /* Send the WMI command */ 579 qdf_status = wmi_unified_dcc_update_ndl(wma_handle->wmi_handle, 580 cmd); 581 /* If there is an error, set the completion event */ 582 if (qdf_status) { 583 WMA_LOGE(FL("Failed to send WMI message: %d"), qdf_status); 584 return -EIO; 585 } 586 587 return 0; 588 } 589 590 /** 591 * wma_dcc_update_ndl_resp_event_handler() - Response event for the update NDL 592 * command 593 * @handle: the WMA handle 594 * @event_buf: buffer with the event parameters 595 * @len: length of the buffer 596 * 597 * Return: 0 on success 598 */ 599 static int wma_dcc_update_ndl_resp_event_handler(void *handle, 600 uint8_t *event_buf, 601 uint32_t len) 602 { 603 QDF_STATUS qdf_status; 604 struct sir_dcc_update_ndl_response *resp; 605 WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *param_tlvs; 606 wmi_dcc_update_ndl_resp_event_fixed_param *fix_param; 607 struct scheduler_msg msg = {0}; 608 609 param_tlvs = (WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *)event_buf; 610 fix_param = param_tlvs->fixed_param; 611 /* Allocate and populate the response */ 612 resp = qdf_mem_malloc(sizeof(*resp)); 613 if (!resp) { 614 WMA_LOGE(FL("Error allocating memory for the response.")); 615 return -ENOMEM; 616 } 617 resp->vdev_id = fix_param->vdev_id; 618 resp->status = fix_param->status; 619 620 msg.type = eWNI_SME_DCC_UPDATE_NDL_RSP; 621 msg.bodyptr = resp; 622 623 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg); 624 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 625 WMA_LOGE(FL("Failed to post msg to SME")); 626 qdf_mem_free(resp); 627 return -EINVAL; 628 } 629 630 return 0; 631 } 632 633 /** 634 * wma_dcc_stats_event_handler() - Response event for the get stats cmd 635 * @handle: the WMA handle 636 * @event_buf: buffer with the event parameters 637 * @len: length of the buffer 638 * 639 * Return: 0 on success 640 */ 641 static int wma_dcc_stats_event_handler(void *handle, uint8_t *event_buf, 642 uint32_t len) 643 { 644 QDF_STATUS qdf_status; 645 struct sir_dcc_get_stats_response *response; 646 WMI_DCC_STATS_EVENTID_param_tlvs *param_tlvs; 647 wmi_dcc_stats_event_fixed_param *fix_param; 648 struct scheduler_msg msg = {0}; 649 650 param_tlvs = (WMI_DCC_STATS_EVENTID_param_tlvs *)event_buf; 651 fix_param = param_tlvs->fixed_param; 652 /* Allocate and populate the response */ 653 if (fix_param->num_channels > ((WMI_SVC_MSG_MAX_SIZE - 654 sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel))) { 655 WMA_LOGE("%s: too many channels:%d", __func__, 656 fix_param->num_channels); 657 QDF_ASSERT(0); 658 return -EINVAL; 659 } 660 response = qdf_mem_malloc(sizeof(*response) + 661 fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel)); 662 if (response == NULL) 663 return -ENOMEM; 664 response->vdev_id = fix_param->vdev_id; 665 response->num_channels = fix_param->num_channels; 666 response->channel_stats_array_len = 667 fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel); 668 669 if (fix_param->num_channels > param_tlvs->num_stats_per_channel_list) { 670 WMA_LOGE("FW message num_chan %d more than TLV hdr %d", 671 fix_param->num_channels, 672 param_tlvs->num_stats_per_channel_list); 673 return -EINVAL; 674 } 675 676 response->channel_stats_array = ((void *)response) + sizeof(*response); 677 qdf_mem_copy(response->channel_stats_array, 678 param_tlvs->stats_per_channel_list, 679 response->channel_stats_array_len); 680 681 msg.type = eWNI_SME_DCC_STATS_EVENT; 682 msg.bodyptr = response; 683 684 qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &msg); 685 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { 686 WMA_LOGE(FL("Failed to post msg to SME")); 687 qdf_mem_free(response); 688 return -EINVAL; 689 } 690 691 return 0; 692 } 693 694 /** 695 * wma_ocb_register_event_handlers() - register handlers for the OCB WMI 696 * events 697 * @wma_handle: pointer to the WMA handle 698 * 699 * Return: 0 on success, non-zero on failure 700 */ 701 int wma_ocb_register_event_handlers(tp_wma_handle wma_handle) 702 { 703 int status; 704 705 if (!wma_handle) { 706 WMA_LOGE(FL("wma_handle is NULL")); 707 return -EINVAL; 708 } 709 710 /* Initialize the members in WMA used by wma_ocb */ 711 status = wmi_unified_register_event_handler(wma_handle->wmi_handle, 712 wmi_ocb_set_config_resp_event_id, 713 wma_ocb_set_config_event_handler, 714 WMA_RX_SERIALIZER_CTX); 715 if (status) 716 return status; 717 718 status = wmi_unified_register_event_handler( 719 wma_handle->wmi_handle, 720 wmi_ocb_get_tsf_timer_resp_event_id, 721 wma_ocb_get_tsf_timer_resp_event_handler, 722 WMA_RX_SERIALIZER_CTX); 723 if (status) 724 return status; 725 726 status = wmi_unified_register_event_handler( 727 wma_handle->wmi_handle, 728 wmi_dcc_get_stats_resp_event_id, 729 wma_dcc_get_stats_resp_event_handler, 730 WMA_RX_SERIALIZER_CTX); 731 if (status) 732 return status; 733 734 status = wmi_unified_register_event_handler( 735 wma_handle->wmi_handle, 736 wmi_dcc_update_ndl_resp_event_id, 737 wma_dcc_update_ndl_resp_event_handler, 738 WMA_RX_SERIALIZER_CTX); 739 if (status) 740 return status; 741 742 status = wmi_unified_register_event_handler(wma_handle->wmi_handle, 743 wmi_dcc_stats_event_id, 744 wma_dcc_stats_event_handler, 745 WMA_RX_SERIALIZER_CTX); 746 if (status) 747 return status; 748 749 return QDF_STATUS_SUCCESS; 750 } 751 752 /** 753 * wma_start_ocb_vdev() - start OCB vdev 754 * @config: ocb channel config 755 * 756 * Return: QDF_STATUS_SUCCESS on success 757 */ 758 static QDF_STATUS wma_start_ocb_vdev(struct ocb_config *config) 759 { 760 struct wma_target_req *msg; 761 struct wma_vdev_start_req req; 762 QDF_STATUS status; 763 tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); 764 765 qdf_mem_zero(&req, sizeof(req)); 766 msg = wma_fill_vdev_req(wma, config->vdev_id, 767 WMA_OCB_SET_CONFIG_CMD, 768 WMA_TARGET_REQ_TYPE_VDEV_START, 769 (void *)config, 1000); 770 if (!msg) { 771 WMA_LOGE(FL("Failed to fill vdev req %d"), config->vdev_id); 772 773 return QDF_STATUS_E_NOMEM; 774 } 775 req.chan = cds_freq_to_chan(config->channels[0].chan_freq); 776 req.vdev_id = msg->vdev_id; 777 if (cds_chan_to_band(req.chan) == CDS_BAND_2GHZ) 778 req.dot11_mode = WNI_CFG_DOT11_MODE_11G; 779 else 780 req.dot11_mode = WNI_CFG_DOT11_MODE_11A; 781 782 req.preferred_rx_streams = 2; 783 req.preferred_tx_streams = 2; 784 785 status = wma_vdev_start(wma, &req, false); 786 if (status != QDF_STATUS_SUCCESS) { 787 wma_remove_vdev_req(wma, req.vdev_id, 788 WMA_TARGET_REQ_TYPE_VDEV_START); 789 WMA_LOGE(FL("vdev_start failed, status = %d"), status); 790 } 791 792 return status; 793 } 794 795 QDF_STATUS wma_ocb_register_callbacks(tp_wma_handle wma_handle) 796 { 797 ucfg_ocb_register_vdev_start(wma_handle->pdev, wma_start_ocb_vdev); 798 799 return QDF_STATUS_SUCCESS; 800 } 801