qcacmn: Add tlv formation of ocb commands in common wmi layer

Move tlv formation of wmi ocb/dsrc commands from umac to
common wmi layer.

Change-Id: I2735b40b97b8ff120e37e343fc6f3681cd0d73f9
CRs-Fixed:983606
diff --git a/wmi_unified_tlv.c b/wmi_unified_tlv.c
index d9f2381..589b12c 100644
--- a/wmi_unified_tlv.c
+++ b/wmi_unified_tlv.c
@@ -261,7 +261,7 @@
 
 /**
  * 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 @@
 
 /**
  * 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 @@
 
 /**
  * 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 @@
 
 /**
  * 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 @@
  * @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 @@
  * @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 @@
 		wmi_buf_free(wmi_buf);
 		return CDF_STATUS_E_FAILURE;
 	}
+
 	return CDF_STATUS_SUCCESS;
 }
 
@@ -1853,6 +1854,645 @@
 	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 @@
 	.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 */
 };