1 /* 2 * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <osdep.h> 20 #include <wmi.h> 21 #include <wmi_unified_priv.h> 22 #include <wmi_unified_concurrency_api.h> 23 24 /** 25 * send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv() -enable/disable 26 * mcc scheduler 27 * @wmi_handle: wmi handle 28 * @mcc_adaptive_scheduler: enable/disable 29 * 30 * This function enable/disable mcc adaptive scheduler in fw. 31 * 32 * Return: QDF_STATUS_SUCCESS for success or error code 33 */ 34 static QDF_STATUS send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv( 35 wmi_unified_t wmi_handle, uint32_t mcc_adaptive_scheduler, 36 uint32_t pdev_id) 37 { 38 QDF_STATUS ret; 39 wmi_buf_t buf = 0; 40 wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *cmd = NULL; 41 uint16_t len = 42 sizeof(wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param); 43 44 buf = wmi_buf_alloc(wmi_handle, len); 45 if (!buf) { 46 return QDF_STATUS_E_NOMEM; 47 } 48 cmd = (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *) 49 wmi_buf_data(buf); 50 51 WMITLV_SET_HDR(&cmd->tlv_header, 52 WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, 53 WMITLV_GET_STRUCT_TLVLEN 54 (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param)); 55 cmd->enable = mcc_adaptive_scheduler; 56 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 57 wmi_handle, 58 pdev_id); 59 60 wmi_mtrace(WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID, NO_SESSION, 0); 61 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 62 WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); 63 if (QDF_IS_STATUS_ERROR(ret)) { 64 WMI_LOGP("%s: Failed to send enable/disable MCC" 65 " adaptive scheduler command", __func__); 66 wmi_buf_free(buf); 67 } 68 69 return ret; 70 } 71 72 /** 73 * send_set_mcc_channel_time_latency_cmd_tlv() -set MCC channel time latency 74 * @wmi: wmi handle 75 * @mcc_channel: mcc channel 76 * @mcc_channel_time_latency: MCC channel time latency. 77 * 78 * Currently used to set time latency for an MCC vdev/adapter using operating 79 * channel of it and channel number. The info is provided run time using 80 * iwpriv command: iwpriv <wlan0 | p2p0> setMccLatency <latency in ms>. 81 * 82 * Return: CDF status 83 */ 84 static QDF_STATUS send_set_mcc_channel_time_latency_cmd_tlv( 85 wmi_unified_t wmi_handle, 86 uint32_t mcc_channel_freq, 87 uint32_t mcc_channel_time_latency) 88 { 89 QDF_STATUS ret; 90 wmi_buf_t buf = 0; 91 wmi_resmgr_set_chan_latency_cmd_fixed_param *cmdTL = NULL; 92 uint16_t len = 0; 93 uint8_t *buf_ptr = NULL; 94 wmi_resmgr_chan_latency chan_latency; 95 /* Note: we only support MCC time latency for a single channel */ 96 uint32_t num_channels = 1; 97 uint32_t chan1_freq = mcc_channel_freq; 98 uint32_t latency_chan1 = mcc_channel_time_latency; 99 100 /* If 0ms latency is provided, then FW will set to a default. 101 * Otherwise, latency must be at least 30ms. 102 */ 103 if ((latency_chan1 > 0) && 104 (latency_chan1 < WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY)) { 105 WMI_LOGE("%s: Invalid time latency for Channel #1 = %dms " 106 "Minimum is 30ms (or 0 to use default value by " 107 "firmware)", __func__, latency_chan1); 108 return QDF_STATUS_E_INVAL; 109 } 110 111 /* Set WMI CMD for channel time latency here */ 112 len = sizeof(wmi_resmgr_set_chan_latency_cmd_fixed_param) + 113 WMI_TLV_HDR_SIZE + /*Place holder for chan_time_latency array */ 114 num_channels * sizeof(wmi_resmgr_chan_latency); 115 buf = wmi_buf_alloc(wmi_handle, len); 116 if (!buf) { 117 return QDF_STATUS_E_NOMEM; 118 } 119 buf_ptr = (uint8_t *) wmi_buf_data(buf); 120 cmdTL = (wmi_resmgr_set_chan_latency_cmd_fixed_param *) 121 wmi_buf_data(buf); 122 WMITLV_SET_HDR(&cmdTL->tlv_header, 123 WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, 124 WMITLV_GET_STRUCT_TLVLEN 125 (wmi_resmgr_set_chan_latency_cmd_fixed_param)); 126 cmdTL->num_chans = num_channels; 127 /* Update channel time latency information for home channel(s) */ 128 buf_ptr += sizeof(*cmdTL); 129 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 130 num_channels * sizeof(wmi_resmgr_chan_latency)); 131 buf_ptr += WMI_TLV_HDR_SIZE; 132 chan_latency.chan_mhz = chan1_freq; 133 chan_latency.latency = latency_chan1; 134 qdf_mem_copy(buf_ptr, &chan_latency, sizeof(chan_latency)); 135 wmi_mtrace(WMI_RESMGR_SET_CHAN_LATENCY_CMDID, NO_SESSION, 0); 136 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 137 WMI_RESMGR_SET_CHAN_LATENCY_CMDID); 138 if (QDF_IS_STATUS_ERROR(ret)) { 139 WMI_LOGE("%s: Failed to send MCC Channel Time Latency command", 140 __func__); 141 wmi_buf_free(buf); 142 QDF_ASSERT(0); 143 } 144 145 return ret; 146 } 147 148 /** 149 * send_set_mcc_channel_time_quota_cmd_tlv() -set MCC channel time quota 150 * @wmi: wmi handle 151 * @adapter_1_chan_number: adapter 1 channel number 152 * @adapter_1_quota: adapter 1 quota 153 * @adapter_2_chan_number: adapter 2 channel number 154 * 155 * Return: CDF status 156 */ 157 static QDF_STATUS send_set_mcc_channel_time_quota_cmd_tlv( 158 wmi_unified_t wmi_handle, 159 uint32_t adapter_1_chan_freq, 160 uint32_t adapter_1_quota, 161 uint32_t adapter_2_chan_freq) 162 { 163 QDF_STATUS ret; 164 wmi_buf_t buf = 0; 165 uint16_t len = 0; 166 uint8_t *buf_ptr = NULL; 167 wmi_resmgr_set_chan_time_quota_cmd_fixed_param *cmdTQ = NULL; 168 wmi_resmgr_chan_time_quota chan_quota; 169 uint32_t quota_chan1 = adapter_1_quota; 170 /* Knowing quota of 1st chan., derive quota for 2nd chan. */ 171 uint32_t quota_chan2 = 100 - quota_chan1; 172 /* Note: setting time quota for MCC requires info for 2 channels */ 173 uint32_t num_channels = 2; 174 uint32_t chan1_freq = adapter_1_chan_freq; 175 uint32_t chan2_freq = adapter_2_chan_freq; 176 177 WMI_LOGD("%s: freq1:%dMHz, Quota1:%dms, " 178 "freq2:%dMHz, Quota2:%dms", __func__, 179 chan1_freq, quota_chan1, chan2_freq, 180 quota_chan2); 181 182 /* 183 * Perform sanity check on time quota values provided. 184 */ 185 if (quota_chan1 < WMI_MCC_MIN_CHANNEL_QUOTA || 186 quota_chan1 > WMI_MCC_MAX_CHANNEL_QUOTA) { 187 WMI_LOGE("%s: Invalid time quota for Channel #1=%dms. Minimum " 188 "is 20ms & maximum is 80ms", __func__, quota_chan1); 189 return QDF_STATUS_E_INVAL; 190 } 191 /* Set WMI CMD for channel time quota here */ 192 len = sizeof(wmi_resmgr_set_chan_time_quota_cmd_fixed_param) + 193 WMI_TLV_HDR_SIZE + /* Place holder for chan_time_quota array */ 194 num_channels * sizeof(wmi_resmgr_chan_time_quota); 195 buf = wmi_buf_alloc(wmi_handle, len); 196 if (!buf) { 197 return QDF_STATUS_E_NOMEM; 198 } 199 buf_ptr = (uint8_t *) wmi_buf_data(buf); 200 cmdTQ = (wmi_resmgr_set_chan_time_quota_cmd_fixed_param *) 201 wmi_buf_data(buf); 202 WMITLV_SET_HDR(&cmdTQ->tlv_header, 203 WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, 204 WMITLV_GET_STRUCT_TLVLEN 205 (wmi_resmgr_set_chan_time_quota_cmd_fixed_param)); 206 cmdTQ->num_chans = num_channels; 207 208 /* Update channel time quota information for home channel(s) */ 209 buf_ptr += sizeof(*cmdTQ); 210 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 211 num_channels * sizeof(wmi_resmgr_chan_time_quota)); 212 buf_ptr += WMI_TLV_HDR_SIZE; 213 chan_quota.chan_mhz = chan1_freq; 214 chan_quota.channel_time_quota = quota_chan1; 215 qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); 216 /* Construct channel and quota record for the 2nd MCC mode. */ 217 buf_ptr += sizeof(chan_quota); 218 chan_quota.chan_mhz = chan2_freq; 219 chan_quota.channel_time_quota = quota_chan2; 220 qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); 221 222 wmi_mtrace(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, NO_SESSION, 0); 223 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 224 WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); 225 if (QDF_IS_STATUS_ERROR(ret)) { 226 WMI_LOGE("Failed to send MCC Channel Time Quota command"); 227 wmi_buf_free(buf); 228 QDF_ASSERT(0); 229 } 230 231 return ret; 232 } 233 234 void wmi_concurrency_attach_tlv(wmi_unified_t wmi_handle) 235 { 236 struct wmi_ops *ops = wmi_handle->ops; 237 238 ops->send_set_enable_disable_mcc_adaptive_scheduler_cmd = 239 send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv; 240 ops->send_set_mcc_channel_time_latency_cmd = 241 send_set_mcc_channel_time_latency_cmd_tlv; 242 ops->send_set_mcc_channel_time_quota_cmd = 243 send_set_mcc_channel_time_quota_cmd_tlv; 244 } 245