diff --git a/wmi_unified_api.c b/wmi_unified_api.c index cce2184eb6..5dfe88288a 100644 --- a/wmi_unified_api.c +++ b/wmi_unified_api.c @@ -769,3 +769,157 @@ wmi_unified_set_sta_uapsd_auto_trig_cmd(void *wmi_hdl, return CDF_STATUS_E_FAILURE; } + +/** + * wmi_unified_ocb_start_timing_advert() - start sending the timing advertisement + * frames on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int32_t wmi_unified_ocb_start_timing_advert(void *wmi_hdl, + struct ocb_timing_advert_param *timing_advert) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_start_timing_advert_cmd) + return wmi_handle->ops->send_ocb_start_timing_advert_cmd(wmi_handle, + timing_advert); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_stop_timing_advert() - stop sending the timing advertisement + * frames on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int32_t wmi_unified_ocb_stop_timing_advert(void *wmi_hdl, + struct ocb_timing_advert_param *timing_advert) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_stop_timing_advert_cmd) + return wmi_handle->ops->send_ocb_stop_timing_advert_cmd(wmi_handle, + timing_advert); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_set_utc_time_cmd() - get ocb tsf timer val + * @wmi_handle: pointer to the wmi handle + * @vdev_id: vdev id + * + * Return: 0 on succes + */ +int32_t wmi_unified_ocb_set_utc_time_cmd(void *wmi_hdl, + struct ocb_utc_param *utc) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_set_utc_time_cmd) + return wmi_handle->ops->send_ocb_set_utc_time_cmd(wmi_handle, + utc); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_get_tsf_timer() - get ocb tsf timer val + * @wmi_handle: pointer to the wmi handle + * @vdev_id: vdev id + * + * Return: 0 on succes + */ +int32_t wmi_unified_ocb_get_tsf_timer(void *wmi_hdl, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_get_tsf_timer_cmd) + return wmi_handle->ops->send_ocb_get_tsf_timer_cmd(wmi_handle, + vdev_id); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dcc_get_stats_cmd() - get the DCC channel stats + * @wmi_handle: pointer to the wmi handle + * @get_stats_param: pointer to the dcc stats + * + * Return: 0 on succes + */ +int32_t wmi_unified_dcc_get_stats_cmd(void *wmi_hdl, + struct dcc_get_stats_param *get_stats_param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dcc_get_stats_cmd) + return wmi_handle->ops->send_dcc_get_stats_cmd(wmi_handle, + get_stats_param); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dcc_clear_stats() - command to clear the DCC stats + * @wmi_handle: pointer to the wmi handle + * @clear_stats_param: parameters to the command + * + * Return: 0 on succes + */ +int32_t wmi_unified_dcc_clear_stats(void *wmi_hdl, + uint32_t vdev_id, uint32_t dcc_stats_bitmap) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dcc_clear_stats_cmd) + return wmi_handle->ops->send_dcc_clear_stats_cmd(wmi_handle, + vdev_id, dcc_stats_bitmap); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dcc_update_ndl() - command to update the NDL data + * @wmi_handle: pointer to the wmi handle + * @update_ndl_param: pointer to the request parameters + * + * Return: 0 on success + */ +int32_t wmi_unified_dcc_update_ndl(void *wmi_hdl, + struct dcc_update_ndl_param *update_ndl_param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dcc_update_ndl_cmd) + return wmi_handle->ops->send_dcc_update_ndl_cmd(wmi_handle, + update_ndl_param); + + return CDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_set_config() - send the OCB config to the FW + * @wmi_handle: pointer to the wmi handle + * @config: the OCB configuration + * + * Return: 0 on success + */ +int32_t wmi_unified_ocb_set_config(void *wmi_hdl, + struct ocb_config_param *config, uint32_t *ch_mhz) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_set_config_cmd) + return wmi_handle->ops->send_ocb_set_config_cmd(wmi_handle, + config, ch_mhz); + + return CDF_STATUS_E_FAILURE; +} diff --git a/wmi_unified_tlv.c b/wmi_unified_tlv.c index d9f23813c6..589b12c22f 100644 --- a/wmi_unified_tlv.c +++ b/wmi_unified_tlv.c @@ -261,7 +261,7 @@ int32_t send_peer_delete_cmd_tlv(wmi_unified_t wmi, /** * send_peer_param_cmd_tlv() - set peer parameter in fw - * @wma_ctx: wmi handle + * @wmi: wmi handle * @peer_addr: peer mac address * @param : pointer to hold peer set parameter * @@ -682,7 +682,7 @@ int32_t send_wow_enable_cmd_tlv(wmi_unified_t wmi_handle, /** * send_set_ap_ps_param_cmd_tlv() - set ap powersave parameters - * @wma_ctx: wma context + * @wmi_handle: wmi handle * @peer_addr: peer mac address * @param: pointer to ap_ps parameter structure * @@ -723,7 +723,7 @@ int32_t send_set_ap_ps_param_cmd_tlv(wmi_unified_t wmi_handle, /** * send_set_sta_ps_param_cmd_tlv() - set sta powersave parameters - * @wma_ctx: wma context + * @wmi_handle: wmi handle * @peer_addr: peer mac address * @param: pointer to sta_ps parameter structure * @@ -764,7 +764,7 @@ int32_t send_set_sta_ps_param_cmd_tlv(wmi_unified_t wmi_handle, /** * send_crash_inject_cmd_tlv() - inject fw crash - * @wma_handle: wma handle + * @wmi_handle: wmi handle * @param: ponirt to crash inject paramter structure * * Return: 0 for success or return error @@ -1632,7 +1632,7 @@ int32_t send_set_smps_params_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id, * @wmi_handle: wmi handle * @noa: p2p power save parameters * - * Return: none + * Return: CDF status */ int32_t send_set_p2pgo_noa_req_cmd_tlv(wmi_unified_t wmi_handle, struct p2p_ps_params *noa) @@ -1700,7 +1700,7 @@ end: * @wmi_handle: wmi handle * @noa: p2p opp power save parameters * - * Return: none + * Return: CDF status */ int32_t send_set_p2pgo_oppps_req_cmd_tlv(wmi_unified_t wmi_handle, struct p2p_ps_params *oppps) @@ -1779,6 +1779,7 @@ int32_t send_get_temperature_cmd_tlv(wmi_unified_t wmi_handle) wmi_buf_free(wmi_buf); return CDF_STATUS_E_FAILURE; } + return CDF_STATUS_SUCCESS; } @@ -1853,6 +1854,645 @@ int32_t send_set_sta_uapsd_auto_trig_cmd_tlv(wmi_unified_t wmi_handle, return ret; } +/** + * send_ocb_set_utc_time_cmd() - send the UTC time to the firmware + * @wmi_handle: pointer to the wmi handle + * @utc: pointer to the UTC time struct + * + * Return: 0 on succes + */ +int send_ocb_set_utc_time_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_utc_param *utc) +{ + int32_t ret; + wmi_ocb_set_utc_time_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len, i; + wmi_buf_t buf; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_set_utc_time_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_utc_time_cmd_fixed_param)); + cmd->vdev_id = utc->vdev_id; + + for (i = 0; i < SIZE_UTC_TIME; i++) + WMI_UTC_TIME_SET(cmd, i, utc->utc_time[i]); + + for (i = 0; i < SIZE_UTC_TIME_ERROR; i++) + WMI_TIME_ERROR_SET(cmd, i, utc->time_error[i]); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_SET_UTC_TIME_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to set OCB UTC time")); + wmi_buf_free(buf); + return -EIO; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * send_ocb_start_timing_advert_cmd_tlv() - start sending the timing advertisement + * frames on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int send_ocb_start_timing_advert_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert) +{ + int32_t ret; + wmi_ocb_start_timing_advert_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len, len_template; + wmi_buf_t buf; + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE; + + len_template = timing_advert->template_length; + /* Add padding to the template if needed */ + if (len_template % 4 != 0) + len_template += 4 - (len_template % 4); + len += len_template; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_start_timing_advert_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_start_timing_advert_cmd_fixed_param)); + cmd->vdev_id = timing_advert->vdev_id; + cmd->repeat_rate = timing_advert->repeat_rate; + cmd->channel_freq = timing_advert->chan_freq; + cmd->timestamp_offset = timing_advert->timestamp_offset; + cmd->time_value_offset = timing_advert->time_value_offset; + cmd->timing_advert_template_length = timing_advert->template_length; + buf_ptr += sizeof(*cmd); + + /* Add the timing advert template */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + len_template); + cdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)timing_advert->template_value, + timing_advert->template_length); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_START_TIMING_ADVERT_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to start OCB timing advert")); + wmi_buf_free(buf); + return -EIO; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * send_ocb_stop_timing_advert_cmd_tlv() - stop sending the timing advertisement frames + * on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int send_ocb_stop_timing_advert_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert) +{ + int32_t ret; + wmi_ocb_stop_timing_advert_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len; + wmi_buf_t buf; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_stop_timing_advert_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_stop_timing_advert_cmd_fixed_param)); + cmd->vdev_id = timing_advert->vdev_id; + cmd->channel_freq = timing_advert->chan_freq; + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_STOP_TIMING_ADVERT_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to stop OCB timing advert")); + wmi_buf_free(buf); + return -EIO; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * send_ocb_get_tsf_timer_cmd_tlv() - get ocb tsf timer val + * @wmi_handle: pointer to the wmi handle + * @request: pointer to the request + * + * Return: 0 on succes + */ +int send_ocb_get_tsf_timer_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + CDF_STATUS ret; + wmi_ocb_get_tsf_timer_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + wmi_buf_t buf; + int32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + cmd = (wmi_ocb_get_tsf_timer_cmd_fixed_param *)buf_ptr; + cdf_mem_zero(cmd, len); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_get_tsf_timer_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_GET_TSF_TIMER_CMDID); + /* If there is an error, set the completion event */ + if (ret != EOK) { + WMA_LOGE(FL("Failed to send WMI message: %d"), ret); + wmi_buf_free(buf); + return -EIO; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * send_dcc_get_stats_cmd_tlv() - get the DCC channel stats + * @wmi_handle: pointer to the wmi handle + * @get_stats_param: pointer to the dcc stats + * + * Return: 0 on succes + */ +int send_dcc_get_stats_cmd_tlv(wmi_unified_t wmi_handle, + struct dcc_get_stats_param *get_stats_param) +{ + int32_t ret; + wmi_dcc_get_stats_cmd_fixed_param *cmd; + wmi_dcc_channel_stats_request *channel_stats_array; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + uint32_t i; + + /* Validate the input */ + if (get_stats_param->request_array_len != + get_stats_param->channel_count * sizeof(*channel_stats_array)) { + WMA_LOGE(FL("Invalid parameter")); + return -EINVAL; + } + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + get_stats_param->request_array_len; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return CDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_get_stats_cmd_fixed_param *)buf_ptr; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_get_stats_cmd_fixed_param)); + cmd->vdev_id = get_stats_param->vdev_id; + cmd->num_channels = get_stats_param->channel_count; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + get_stats_param->request_array_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + channel_stats_array = (wmi_dcc_channel_stats_request *)buf_ptr; + cdf_mem_copy(channel_stats_array, get_stats_param->request_array, + get_stats_param->request_array_len); + for (i = 0; i < cmd->num_channels; i++) + WMITLV_SET_HDR(&channel_stats_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_channel_stats_request)); + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DCC_GET_STATS_CMDID); + + if (ret != EOK) { + WMA_LOGE(FL("Failed to send WMI message: %d"), ret); + wmi_buf_free(buf); + return -EIO; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * send_dcc_clear_stats_cmd_tlv() - command to clear the DCC stats + * @wmi_handle: pointer to the wmi handle + * @vdev_id: vdev id + * @dcc_stats_bitmap: dcc status bitmap + * + * Return: 0 on succes + */ +int send_dcc_clear_stats_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t dcc_stats_bitmap) +{ + int32_t ret; + wmi_dcc_clear_stats_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_clear_stats_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_clear_stats_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->dcc_stats_bitmap = dcc_stats_bitmap; + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DCC_CLEAR_STATS_CMDID); + if (ret != EOK) { + WMA_LOGE(FL("Failed to send the WMI command")); + wmi_buf_free(buf); + return -EIO; + } + + return CDF_STATUS_SUCCESS; +} + +/** + * send_dcc_update_ndl_cmd_tlv() - command to update the NDL data + * @wmi_handle: pointer to the wmi handle + * @update_ndl_param: pointer to the request parameters + * + * Return: 0 on success + */ +int send_dcc_update_ndl_cmd_tlv(wmi_unified_t wmi_handle, + struct dcc_update_ndl_param *update_ndl_param) +{ + CDF_STATUS cdf_status; + wmi_dcc_update_ndl_cmd_fixed_param *cmd; + wmi_dcc_ndl_chan *ndl_chan_array; + wmi_dcc_ndl_active_state_config *ndl_active_state_array; + uint32_t active_state_count; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + uint32_t i; + + /* validate the input */ + if (update_ndl_param->dcc_ndl_chan_list_len != + update_ndl_param->channel_count * sizeof(*ndl_chan_array)) { + WMA_LOGE(FL("Invalid parameter")); + return CDF_STATUS_E_INVAL; + } + active_state_count = 0; + ndl_chan_array = update_ndl_param->dcc_ndl_chan_list; + for (i = 0; i < update_ndl_param->channel_count; i++) + active_state_count += + WMI_NDL_NUM_ACTIVE_STATE_GET(&ndl_chan_array[i]); + if (update_ndl_param->dcc_ndl_active_state_list_len != + active_state_count * sizeof(*ndl_active_state_array)) { + WMA_LOGE(FL("Invalid parameter")); + return CDF_STATUS_E_INVAL; + } + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + update_ndl_param->dcc_ndl_chan_list_len + + WMI_TLV_HDR_SIZE + + update_ndl_param->dcc_ndl_active_state_list_len; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = wmi_buf_data(buf); + cdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_update_ndl_cmd_fixed_param *)buf_ptr; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_update_ndl_cmd_fixed_param)); + cmd->vdev_id = update_ndl_param->vdev_id; + cmd->num_channel = update_ndl_param->channel_count; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + update_ndl_param->dcc_ndl_chan_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + ndl_chan_array = (wmi_dcc_ndl_chan *)buf_ptr; + cdf_mem_copy(ndl_chan_array, update_ndl_param->dcc_ndl_chan_list, + update_ndl_param->dcc_ndl_chan_list_len); + for (i = 0; i < cmd->num_channel; i++) + WMITLV_SET_HDR(&ndl_chan_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_chan)); + buf_ptr += update_ndl_param->dcc_ndl_chan_list_len; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + update_ndl_param->dcc_ndl_active_state_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + ndl_active_state_array = (wmi_dcc_ndl_active_state_config *) buf_ptr; + cdf_mem_copy(ndl_active_state_array, + update_ndl_param->dcc_ndl_active_state_list, + update_ndl_param->dcc_ndl_active_state_list_len); + for (i = 0; i < active_state_count; i++) { + WMITLV_SET_HDR(&ndl_active_state_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_active_state_config)); + } + buf_ptr += update_ndl_param->dcc_ndl_active_state_list_len; + + /* Send the WMI command */ + cdf_status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DCC_UPDATE_NDL_CMDID); + /* If there is an error, set the completion event */ + if (cdf_status) { + WMA_LOGE(FL("Failed to send WMI message: %d"), cdf_status); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} + +/** + * send_ocb_set_config_cmd_tlv() - send the OCB config to the FW + * @wmi_handle: pointer to the wmi handle + * @config: the OCB configuration + * + * Return: 0 on success + */ +int send_ocb_set_config_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_config_param *config, uint32_t *ch_mhz) +{ + int32_t ret; + wmi_ocb_set_config_cmd_fixed_param *cmd; + wmi_channel *chan; + wmi_ocb_channel *ocb_chan; + wmi_qos_parameter *qos_param; + wmi_dcc_ndl_chan *ndl_chan; + wmi_dcc_ndl_active_state_config *ndl_active_config; + wmi_ocb_schedule_element *sched_elem; + uint8_t *buf_ptr; + wmi_buf_t buf; + int32_t len; + int32_t i, j, active_state_count; + + /* + * Validate the dcc_ndl_chan_list_len and count the number of active + * states. Validate dcc_ndl_active_state_list_len. + */ + active_state_count = 0; + if (config->dcc_ndl_chan_list_len) { + if (!config->dcc_ndl_chan_list || + config->dcc_ndl_chan_list_len != + config->channel_count * sizeof(wmi_dcc_ndl_chan)) { + WMA_LOGE(FL("NDL channel is invalid. List len: %d"), + config->dcc_ndl_chan_list_len); + return -EINVAL; + } + + for (i = 0, ndl_chan = config->dcc_ndl_chan_list; + i < config->channel_count; ++i, ++ndl_chan) + active_state_count += + WMI_NDL_NUM_ACTIVE_STATE_GET(ndl_chan); + + if (active_state_count) { + if (!config->dcc_ndl_active_state_list || + config->dcc_ndl_active_state_list_len != + active_state_count * + sizeof(wmi_dcc_ndl_active_state_config)) { + WMA_LOGE(FL("NDL active state is invalid.")); + return -EINVAL; + } + } + } + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_channel) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_ocb_channel) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_qos_parameter) * WMI_MAX_NUM_AC + + WMI_TLV_HDR_SIZE + config->dcc_ndl_chan_list_len + + WMI_TLV_HDR_SIZE + active_state_count * + sizeof(wmi_dcc_ndl_active_state_config) + + WMI_TLV_HDR_SIZE + config->schedule_size * + sizeof(wmi_ocb_schedule_element); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return -ENOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_set_config_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_config_cmd_fixed_param)); + cmd->vdev_id = config->session_id; + cmd->channel_count = config->channel_count; + cmd->schedule_size = config->schedule_size; + cmd->flags = config->flags; + buf_ptr += sizeof(*cmd); + + /* Add the wmi_channel info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count*sizeof(wmi_channel)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->channel_count; i++) { + chan = (wmi_channel *)buf_ptr; + WMITLV_SET_HDR(&chan->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan->mhz = config->channels[i].chan_freq; + chan->band_center_freq1 = config->channels[i].chan_freq; + chan->band_center_freq2 = 0; + chan->info = 0; + + WMI_SET_CHANNEL_MODE(chan, ch_mhz[i]); + WMI_SET_CHANNEL_MAX_POWER(chan, config->channels[i].max_pwr); + WMI_SET_CHANNEL_MIN_POWER(chan, config->channels[i].min_pwr); + WMI_SET_CHANNEL_MAX_TX_POWER(chan, config->channels[i].max_pwr); + WMI_SET_CHANNEL_REG_POWER(chan, config->channels[i].reg_pwr); + WMI_SET_CHANNEL_ANTENNA_MAX(chan, + config->channels[i].antenna_max); + + if (config->channels[i].bandwidth < 10) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE); + else if (config->channels[i].bandwidth < 20) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE); + buf_ptr += sizeof(*chan); + } + + /* Add the wmi_ocb_channel info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count*sizeof(wmi_ocb_channel)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->channel_count; i++) { + ocb_chan = (wmi_ocb_channel *)buf_ptr; + WMITLV_SET_HDR(&ocb_chan->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_channel)); + ocb_chan->bandwidth = config->channels[i].bandwidth; + WMI_CHAR_ARRAY_TO_MAC_ADDR( + config->channels[i].mac_address.bytes, + &ocb_chan->mac_address); + buf_ptr += sizeof(*ocb_chan); + } + + /* Add the wmi_qos_parameter info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count * sizeof(wmi_qos_parameter)*WMI_MAX_NUM_AC); + buf_ptr += WMI_TLV_HDR_SIZE; + /* WMI_MAX_NUM_AC parameters for each channel */ + for (i = 0; i < config->channel_count; i++) { + for (j = 0; j < WMI_MAX_NUM_AC; j++) { + qos_param = (wmi_qos_parameter *)buf_ptr; + WMITLV_SET_HDR(&qos_param->tlv_header, + WMITLV_TAG_STRUC_wmi_qos_parameter, + WMITLV_GET_STRUCT_TLVLEN(wmi_qos_parameter)); + qos_param->aifsn = + config->channels[i].qos_params[j].aifsn; + qos_param->cwmin = + config->channels[i].qos_params[j].cwmin; + qos_param->cwmax = + config->channels[i].qos_params[j].cwmax; + buf_ptr += sizeof(*qos_param); + } + } + + /* Add the wmi_dcc_ndl_chan (per channel) */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->dcc_ndl_chan_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + if (config->dcc_ndl_chan_list_len) { + ndl_chan = (wmi_dcc_ndl_chan *)buf_ptr; + cdf_mem_copy(ndl_chan, config->dcc_ndl_chan_list, + config->dcc_ndl_chan_list_len); + for (i = 0; i < config->channel_count; i++) + WMITLV_SET_HDR(&(ndl_chan[i].tlv_header), + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_GET_STRUCT_TLVLEN(wmi_dcc_ndl_chan)); + buf_ptr += config->dcc_ndl_chan_list_len; + } + + /* Add the wmi_dcc_ndl_active_state_config */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, active_state_count * + sizeof(wmi_dcc_ndl_active_state_config)); + buf_ptr += WMI_TLV_HDR_SIZE; + if (active_state_count) { + ndl_active_config = (wmi_dcc_ndl_active_state_config *)buf_ptr; + cdf_mem_copy(ndl_active_config, + config->dcc_ndl_active_state_list, + active_state_count * sizeof(*ndl_active_config)); + for (i = 0; i < active_state_count; ++i) + WMITLV_SET_HDR(&(ndl_active_config[i].tlv_header), + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_active_state_config)); + buf_ptr += active_state_count * + sizeof(*ndl_active_config); + } + + /* Add the wmi_ocb_schedule_element info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->schedule_size * sizeof(wmi_ocb_schedule_element)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->schedule_size; i++) { + sched_elem = (wmi_ocb_schedule_element *)buf_ptr; + WMITLV_SET_HDR(&sched_elem->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_schedule_element, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_schedule_element)); + sched_elem->channel_freq = config->schedule[i].chan_freq; + sched_elem->total_duration = config->schedule[i].total_duration; + sched_elem->guard_interval = config->schedule[i].guard_interval; + buf_ptr += sizeof(*sched_elem); + } + + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_SET_CONFIG_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to set OCB config"); + wmi_buf_free(buf); + return -EIO; + } + + return 0; +} struct wmi_ops tlv_ops = { .send_vdev_create_cmd = send_vdev_create_cmd_tlv, .send_vdev_delete_cmd = send_vdev_delete_cmd_tlv, @@ -1890,6 +2530,14 @@ struct wmi_ops tlv_ops = { .send_set_p2pgo_noa_req_cmd = send_set_p2pgo_noa_req_cmd_tlv, .send_set_smps_params_cmd = send_set_smps_params_cmd_tlv, .send_set_mimops_cmd = send_set_mimops_cmd_tlv, + .send_ocb_set_utc_time_cmd = send_ocb_set_utc_time_cmd_tlv, + .send_ocb_get_tsf_timer_cmd = send_ocb_get_tsf_timer_cmd_tlv, + .send_dcc_clear_stats_cmd = send_dcc_clear_stats_cmd_tlv, + .send_dcc_get_stats_cmd = send_dcc_get_stats_cmd_tlv, + .send_dcc_update_ndl_cmd = send_dcc_update_ndl_cmd_tlv, + .send_ocb_set_config_cmd = send_ocb_set_config_cmd_tlv, + .send_ocb_stop_timing_advert_cmd = send_ocb_stop_timing_advert_cmd_tlv, + .send_ocb_start_timing_advert_cmd = send_ocb_start_timing_advert_cmd_tlv, /* TODO - Add other tlv apis here */ };