
The kernel-doc script identified many documentation issues in the wmi folder, so fix them. Note that in quite a few cases there is duplicate documentation in .h and .c files, and in those cases remove the documentation from the .c files since the interface should be documented, not the implementation. Change-Id: I097d5b8e8f0ba09046b7b8abe338d05a00f8cc7e CRs-Fixed: 3372831
794 lines
25 KiB
C
794 lines
25 KiB
C
/*
|
|
* Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
|
|
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for
|
|
* any purpose with or without fee is hereby granted, provided that the
|
|
* above copyright notice and this permission notice appear in all
|
|
* copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
|
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
|
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <osdep.h>
|
|
#include <wmi.h>
|
|
#include <wmi_unified_priv.h>
|
|
#include <wlan_ocb_public_structs.h>
|
|
#include <wmi_unified_ocb_api.h>
|
|
|
|
/**
|
|
* send_ocb_set_utc_time_cmd_tlv() - send the UTC time to the firmware
|
|
* @wmi_handle: pointer to the wmi handle
|
|
* @utc: pointer to the UTC time struct
|
|
*
|
|
* Return: 0 on success
|
|
*/
|
|
static QDF_STATUS send_ocb_set_utc_time_cmd_tlv(wmi_unified_t wmi_handle,
|
|
struct ocb_utc_param *utc)
|
|
{
|
|
QDF_STATUS 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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
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]);
|
|
|
|
wmi_mtrace(WMI_OCB_SET_UTC_TIME_CMDID, cmd->vdev_id, 0);
|
|
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
|
|
WMI_OCB_SET_UTC_TIME_CMDID);
|
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
|
wmi_err("Failed to set OCB UTC time");
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 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 success
|
|
*/
|
|
static QDF_STATUS send_ocb_start_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,
|
|
struct ocb_timing_advert_param *timing_advert)
|
|
{
|
|
QDF_STATUS 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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
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);
|
|
qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
|
|
(uint8_t *)timing_advert->template_value,
|
|
timing_advert->template_length);
|
|
|
|
wmi_mtrace(WMI_OCB_START_TIMING_ADVERT_CMDID, cmd->vdev_id, 0);
|
|
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
|
|
WMI_OCB_START_TIMING_ADVERT_CMDID);
|
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
|
wmi_err("Failed to start OCB timing advert");
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 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 success
|
|
*/
|
|
static QDF_STATUS send_ocb_stop_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,
|
|
struct ocb_timing_advert_param *timing_advert)
|
|
{
|
|
QDF_STATUS 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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
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;
|
|
|
|
wmi_mtrace(WMI_OCB_STOP_TIMING_ADVERT_CMDID, cmd->vdev_id, 0);
|
|
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
|
|
WMI_OCB_STOP_TIMING_ADVERT_CMDID);
|
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
|
wmi_err("Failed to stop OCB timing advert");
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* send_ocb_get_tsf_timer_cmd_tlv() - get ocb tsf timer val
|
|
* @wmi_handle: pointer to the wmi handle
|
|
* @vdev_id: vdev identifier
|
|
*
|
|
* Return: 0 on success
|
|
*/
|
|
static QDF_STATUS send_ocb_get_tsf_timer_cmd_tlv(wmi_unified_t wmi_handle,
|
|
uint8_t vdev_id)
|
|
{
|
|
QDF_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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
buf_ptr = (uint8_t *)wmi_buf_data(buf);
|
|
|
|
cmd = (wmi_ocb_get_tsf_timer_cmd_fixed_param *)buf_ptr;
|
|
qdf_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 */
|
|
wmi_mtrace(WMI_OCB_GET_TSF_TIMER_CMDID, cmd->vdev_id, 0);
|
|
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 (QDF_IS_STATUS_ERROR(ret)) {
|
|
wmi_err("Failed to send WMI message: %d", ret);
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 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 success
|
|
*/
|
|
static QDF_STATUS send_dcc_get_stats_cmd_tlv(wmi_unified_t wmi_handle,
|
|
struct ocb_dcc_get_stats_param *get_stats_param)
|
|
{
|
|
QDF_STATUS 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)) {
|
|
wmi_err("Invalid parameter");
|
|
return QDF_STATUS_E_INVAL;
|
|
}
|
|
|
|
/* 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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
buf_ptr = wmi_buf_data(buf);
|
|
qdf_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;
|
|
qdf_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 */
|
|
wmi_mtrace(WMI_DCC_GET_STATS_CMDID, cmd->vdev_id, 0);
|
|
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
|
|
WMI_DCC_GET_STATS_CMDID);
|
|
|
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
|
wmi_err("Failed to send WMI message: %d", ret);
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 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 success
|
|
*/
|
|
static QDF_STATUS send_dcc_clear_stats_cmd_tlv(wmi_unified_t wmi_handle,
|
|
uint32_t vdev_id, uint32_t dcc_stats_bitmap)
|
|
{
|
|
QDF_STATUS 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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
buf_ptr = wmi_buf_data(buf);
|
|
qdf_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 */
|
|
wmi_mtrace(WMI_DCC_CLEAR_STATS_CMDID, cmd->vdev_id, 0);
|
|
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
|
|
WMI_DCC_CLEAR_STATS_CMDID);
|
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
|
wmi_err("Failed to send the WMI command");
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
static QDF_STATUS send_dcc_update_ndl_cmd_tlv(wmi_unified_t wmi_handle,
|
|
struct ocb_dcc_update_ndl_param *update_ndl_param)
|
|
{
|
|
QDF_STATUS qdf_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)) {
|
|
wmi_err("Invalid parameter");
|
|
return QDF_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)) {
|
|
wmi_err("Invalid parameter");
|
|
return QDF_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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
buf_ptr = wmi_buf_data(buf);
|
|
qdf_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;
|
|
qdf_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;
|
|
qdf_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 */
|
|
wmi_mtrace(WMI_DCC_UPDATE_NDL_CMDID, cmd->vdev_id, 0);
|
|
qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len,
|
|
WMI_DCC_UPDATE_NDL_CMDID);
|
|
/* If there is an error, set the completion event */
|
|
if (QDF_IS_STATUS_ERROR(qdf_status)) {
|
|
wmi_err("Failed to send WMI message: %d", qdf_status);
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return qdf_status;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
static QDF_STATUS send_ocb_set_config_cmd_tlv(wmi_unified_t wmi_handle,
|
|
struct ocb_config *config)
|
|
{
|
|
QDF_STATUS 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)) {
|
|
wmi_err("NDL channel is invalid. List len: %d",
|
|
config->dcc_ndl_chan_list_len);
|
|
return QDF_STATUS_E_INVAL;
|
|
}
|
|
|
|
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)) {
|
|
wmi_err("NDL active state is invalid");
|
|
return QDF_STATUS_E_INVAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
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) {
|
|
return QDF_STATUS_E_NOMEM;
|
|
}
|
|
|
|
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->vdev_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, config->channels[i].ch_mode);
|
|
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;
|
|
qdf_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;
|
|
qdf_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);
|
|
}
|
|
|
|
wmi_mtrace(WMI_OCB_SET_CONFIG_CMDID, cmd->vdev_id, 0);
|
|
ret = wmi_unified_cmd_send(wmi_handle, buf, len,
|
|
WMI_OCB_SET_CONFIG_CMDID);
|
|
if (QDF_IS_STATUS_ERROR(ret)) {
|
|
wmi_err("Failed to set OCB config");
|
|
wmi_buf_free(buf);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* extract_ocb_channel_config_resp_tlv() - extract ocb channel config resp
|
|
* @wmi_handle: wmi handle
|
|
* @evt_buf: wmi event buffer
|
|
* @status: status buffer
|
|
*
|
|
* Return: QDF_STATUS_SUCCESS on success
|
|
*/
|
|
static QDF_STATUS extract_ocb_channel_config_resp_tlv(wmi_unified_t wmi_handle,
|
|
void *evt_buf,
|
|
uint32_t *status)
|
|
{
|
|
WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *param_tlvs;
|
|
wmi_ocb_set_config_resp_event_fixed_param *fix_param;
|
|
|
|
param_tlvs = evt_buf;
|
|
fix_param = param_tlvs->fixed_param;
|
|
|
|
*status = fix_param->status;
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* extract_ocb_tsf_timer_tlv() - extract TSF timer from event buffer
|
|
* @wmi_handle: wmi handle
|
|
* @evt_buf: wmi event buffer
|
|
* @resp: response buffer
|
|
*
|
|
* Return: QDF_STATUS_SUCCESS on success
|
|
*/
|
|
static QDF_STATUS extract_ocb_tsf_timer_tlv(wmi_unified_t wmi_handle,
|
|
void *evt_buf, struct ocb_get_tsf_timer_response *resp)
|
|
{
|
|
WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *param_tlvs;
|
|
wmi_ocb_get_tsf_timer_resp_event_fixed_param *fix_param;
|
|
|
|
param_tlvs = evt_buf;
|
|
fix_param = param_tlvs->fixed_param;
|
|
resp->vdev_id = fix_param->vdev_id;
|
|
resp->timer_high = fix_param->tsf_timer_high;
|
|
resp->timer_low = fix_param->tsf_timer_low;
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* extract_ocb_ndl_resp_tlv() - extract TSF timer from event buffer
|
|
* @wmi_handle: wmi handle
|
|
* @evt_buf: wmi event buffer
|
|
* @resp: response buffer
|
|
*
|
|
* Return: QDF_STATUS_SUCCESS on success
|
|
*/
|
|
static QDF_STATUS extract_ocb_ndl_resp_tlv(wmi_unified_t wmi_handle,
|
|
void *evt_buf, struct ocb_dcc_update_ndl_response *resp)
|
|
{
|
|
WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *param_tlvs;
|
|
wmi_dcc_update_ndl_resp_event_fixed_param *fix_param;
|
|
|
|
param_tlvs = evt_buf;
|
|
fix_param = param_tlvs->fixed_param;
|
|
resp->vdev_id = fix_param->vdev_id;
|
|
resp->status = fix_param->status;
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* extract_ocb_dcc_stats_tlv() - extract DCC stats from event buffer
|
|
* @wmi_handle: wmi handle
|
|
* @evt_buf: wmi event buffer
|
|
* @resp: response buffer
|
|
*
|
|
* Since length of stats is variable, buffer for DCC stats will be allocated
|
|
* in this function. The caller must free the buffer.
|
|
*
|
|
* Return: QDF_STATUS_SUCCESS on success
|
|
*/
|
|
static QDF_STATUS extract_ocb_dcc_stats_tlv(wmi_unified_t wmi_handle,
|
|
void *evt_buf, struct ocb_dcc_get_stats_response **resp)
|
|
{
|
|
struct ocb_dcc_get_stats_response *response;
|
|
WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *param_tlvs;
|
|
wmi_dcc_get_stats_resp_event_fixed_param *fix_param;
|
|
|
|
param_tlvs = (WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *)evt_buf;
|
|
fix_param = param_tlvs->fixed_param;
|
|
|
|
/* Allocate and populate the response */
|
|
if (fix_param->num_channels > ((WMI_SVC_MSG_MAX_SIZE -
|
|
sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel)) ||
|
|
fix_param->num_channels > param_tlvs->num_stats_per_channel_list) {
|
|
wmi_warn("Too many channels:%d actual:%d",
|
|
fix_param->num_channels,
|
|
param_tlvs->num_stats_per_channel_list);
|
|
*resp = NULL;
|
|
return QDF_STATUS_E_INVAL;
|
|
}
|
|
response = qdf_mem_malloc(sizeof(*response) + fix_param->num_channels *
|
|
sizeof(wmi_dcc_ndl_stats_per_channel));
|
|
*resp = response;
|
|
if (!response)
|
|
return QDF_STATUS_E_NOMEM;
|
|
|
|
response->vdev_id = fix_param->vdev_id;
|
|
response->num_channels = fix_param->num_channels;
|
|
response->channel_stats_array_len =
|
|
fix_param->num_channels *
|
|
sizeof(wmi_dcc_ndl_stats_per_channel);
|
|
response->channel_stats_array = ((uint8_t *)response) +
|
|
sizeof(*response);
|
|
qdf_mem_copy(response->channel_stats_array,
|
|
param_tlvs->stats_per_channel_list,
|
|
response->channel_stats_array_len);
|
|
|
|
return QDF_STATUS_SUCCESS;
|
|
}
|
|
|
|
void wmi_ocb_attach_tlv(wmi_unified_t wmi_handle)
|
|
{
|
|
struct wmi_ops *ops = wmi_handle->ops;
|
|
|
|
ops->send_ocb_set_utc_time_cmd = send_ocb_set_utc_time_cmd_tlv;
|
|
ops->send_ocb_get_tsf_timer_cmd = send_ocb_get_tsf_timer_cmd_tlv;
|
|
ops->send_dcc_clear_stats_cmd = send_dcc_clear_stats_cmd_tlv;
|
|
ops->send_dcc_get_stats_cmd = send_dcc_get_stats_cmd_tlv;
|
|
ops->send_dcc_update_ndl_cmd = send_dcc_update_ndl_cmd_tlv;
|
|
ops->send_ocb_set_config_cmd = send_ocb_set_config_cmd_tlv;
|
|
ops->send_ocb_stop_timing_advert_cmd =
|
|
send_ocb_stop_timing_advert_cmd_tlv;
|
|
ops->send_ocb_start_timing_advert_cmd =
|
|
send_ocb_start_timing_advert_cmd_tlv;
|
|
ops->extract_ocb_chan_config_resp =
|
|
extract_ocb_channel_config_resp_tlv;
|
|
ops->extract_ocb_tsf_timer = extract_ocb_tsf_timer_tlv;
|
|
ops->extract_dcc_update_ndl_resp = extract_ocb_ndl_resp_tlv;
|
|
ops->extract_dcc_stats = extract_ocb_dcc_stats_tlv;
|
|
}
|