1 /* 2 * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <osdep.h> 21 #include <wmi.h> 22 #include <wmi_unified_priv.h> 23 #include <wmi_unified_concurrency_api.h> 24 #ifdef WLAN_FEATURE_MCC_QUOTA 25 #include <wlan_p2p_mcc_quota_public_struct.h> 26 #endif 27 28 /** 29 * send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv() -enable/disable 30 * mcc scheduler 31 * @wmi_handle: wmi handle 32 * @mcc_adaptive_scheduler: enable/disable 33 * 34 * This function enable/disable mcc adaptive scheduler in fw. 35 * 36 * Return: QDF_STATUS_SUCCESS for success or error code 37 */ 38 static QDF_STATUS send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv( 39 wmi_unified_t wmi_handle, uint32_t mcc_adaptive_scheduler, 40 uint32_t pdev_id) 41 { 42 QDF_STATUS ret; 43 wmi_buf_t buf = 0; 44 wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *cmd = NULL; 45 uint16_t len = 46 sizeof(wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param); 47 48 buf = wmi_buf_alloc(wmi_handle, len); 49 if (!buf) { 50 return QDF_STATUS_E_NOMEM; 51 } 52 cmd = (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *) 53 wmi_buf_data(buf); 54 55 WMITLV_SET_HDR(&cmd->tlv_header, 56 WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, 57 WMITLV_GET_STRUCT_TLVLEN 58 (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param)); 59 cmd->enable = mcc_adaptive_scheduler; 60 cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( 61 wmi_handle, 62 pdev_id); 63 64 wmi_mtrace(WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID, NO_SESSION, 0); 65 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 66 WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); 67 if (QDF_IS_STATUS_ERROR(ret)) { 68 wmi_err("Failed to send enable/disable MCC" 69 " adaptive scheduler command"); 70 wmi_buf_free(buf); 71 } 72 73 return ret; 74 } 75 76 /** 77 * send_set_mcc_channel_time_latency_cmd_tlv() -set MCC channel time latency 78 * @wmi: wmi handle 79 * @mcc_channel: mcc channel 80 * @mcc_channel_time_latency: MCC channel time latency. 81 * 82 * Currently used to set time latency for an MCC vdev/adapter using operating 83 * channel of it and channel number. The info is provided run time using 84 * iwpriv command: iwpriv <wlan0 | p2p0> setMccLatency <latency in ms>. 85 * 86 * Return: CDF status 87 */ 88 static QDF_STATUS send_set_mcc_channel_time_latency_cmd_tlv( 89 wmi_unified_t wmi_handle, 90 uint32_t mcc_channel_freq, 91 uint32_t mcc_channel_time_latency) 92 { 93 QDF_STATUS ret; 94 wmi_buf_t buf = 0; 95 wmi_resmgr_set_chan_latency_cmd_fixed_param *cmdTL = NULL; 96 uint16_t len = 0; 97 uint8_t *buf_ptr = NULL; 98 wmi_resmgr_chan_latency chan_latency; 99 /* Note: we only support MCC time latency for a single channel */ 100 uint32_t num_channels = 1; 101 uint32_t chan1_freq = mcc_channel_freq; 102 uint32_t latency_chan1 = mcc_channel_time_latency; 103 104 /* If 0ms latency is provided, then FW will set to a default. 105 * Otherwise, latency must be at least 30ms. 106 */ 107 if ((latency_chan1 > 0) && 108 (latency_chan1 < WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY)) { 109 wmi_err("Invalid time latency for Channel #1 = %dms " 110 "Minimum is 30ms (or 0 to use default value by " 111 "firmware)", latency_chan1); 112 return QDF_STATUS_E_INVAL; 113 } 114 115 /* Set WMI CMD for channel time latency here */ 116 len = sizeof(wmi_resmgr_set_chan_latency_cmd_fixed_param) + 117 WMI_TLV_HDR_SIZE + /*Place holder for chan_time_latency array */ 118 num_channels * sizeof(wmi_resmgr_chan_latency); 119 buf = wmi_buf_alloc(wmi_handle, len); 120 if (!buf) { 121 return QDF_STATUS_E_NOMEM; 122 } 123 buf_ptr = (uint8_t *) wmi_buf_data(buf); 124 cmdTL = (wmi_resmgr_set_chan_latency_cmd_fixed_param *) 125 wmi_buf_data(buf); 126 WMITLV_SET_HDR(&cmdTL->tlv_header, 127 WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, 128 WMITLV_GET_STRUCT_TLVLEN 129 (wmi_resmgr_set_chan_latency_cmd_fixed_param)); 130 cmdTL->num_chans = num_channels; 131 /* Update channel time latency information for home channel(s) */ 132 buf_ptr += sizeof(*cmdTL); 133 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 134 num_channels * sizeof(wmi_resmgr_chan_latency)); 135 buf_ptr += WMI_TLV_HDR_SIZE; 136 chan_latency.chan_mhz = chan1_freq; 137 chan_latency.latency = latency_chan1; 138 qdf_mem_copy(buf_ptr, &chan_latency, sizeof(chan_latency)); 139 wmi_mtrace(WMI_RESMGR_SET_CHAN_LATENCY_CMDID, NO_SESSION, 0); 140 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 141 WMI_RESMGR_SET_CHAN_LATENCY_CMDID); 142 if (QDF_IS_STATUS_ERROR(ret)) { 143 wmi_err("Failed to send MCC Channel Time Latency command"); 144 wmi_buf_free(buf); 145 QDF_ASSERT(0); 146 } 147 148 return ret; 149 } 150 151 /** 152 * send_set_mcc_channel_time_quota_cmd_tlv() -set MCC channel time quota 153 * @wmi: wmi handle 154 * @adapter_1_chan_number: adapter 1 channel number 155 * @adapter_1_quota: adapter 1 quota 156 * @adapter_2_chan_number: adapter 2 channel number 157 * 158 * Return: CDF status 159 */ 160 static QDF_STATUS send_set_mcc_channel_time_quota_cmd_tlv( 161 wmi_unified_t wmi_handle, 162 uint32_t adapter_1_chan_freq, 163 uint32_t adapter_1_quota, 164 uint32_t adapter_2_chan_freq) 165 { 166 QDF_STATUS ret; 167 wmi_buf_t buf = 0; 168 uint16_t len = 0; 169 uint8_t *buf_ptr = NULL; 170 wmi_resmgr_set_chan_time_quota_cmd_fixed_param *cmdTQ = NULL; 171 wmi_resmgr_chan_time_quota chan_quota; 172 uint32_t quota_chan1 = adapter_1_quota; 173 /* Knowing quota of 1st chan., derive quota for 2nd chan. */ 174 uint32_t quota_chan2 = 100 - quota_chan1; 175 /* Note: setting time quota for MCC requires info for 2 channels */ 176 uint32_t num_channels = 2; 177 uint32_t chan1_freq = adapter_1_chan_freq; 178 uint32_t chan2_freq = adapter_2_chan_freq; 179 180 wmi_debug("freq1:%dMHz, Quota1:%dms, freq2:%dMHz, Quota2:%dms", 181 chan1_freq, quota_chan1, chan2_freq, quota_chan2); 182 183 /* 184 * Perform sanity check on time quota values provided. 185 */ 186 if (quota_chan1 < WMI_MCC_MIN_CHANNEL_QUOTA || 187 quota_chan1 > WMI_MCC_MAX_CHANNEL_QUOTA) { 188 wmi_err("Invalid time quota for Chan #1=%dms. Min: %dms, Max: %dms", 189 quota_chan1, WMI_MCC_MIN_CHANNEL_QUOTA, 190 WMI_MCC_MAX_CHANNEL_QUOTA); 191 return QDF_STATUS_E_INVAL; 192 } 193 /* Set WMI CMD for channel time quota here */ 194 len = sizeof(wmi_resmgr_set_chan_time_quota_cmd_fixed_param) + 195 WMI_TLV_HDR_SIZE + /* Place holder for chan_time_quota array */ 196 num_channels * sizeof(wmi_resmgr_chan_time_quota); 197 buf = wmi_buf_alloc(wmi_handle, len); 198 if (!buf) { 199 return QDF_STATUS_E_NOMEM; 200 } 201 buf_ptr = (uint8_t *) wmi_buf_data(buf); 202 cmdTQ = (wmi_resmgr_set_chan_time_quota_cmd_fixed_param *) 203 wmi_buf_data(buf); 204 WMITLV_SET_HDR(&cmdTQ->tlv_header, 205 WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, 206 WMITLV_GET_STRUCT_TLVLEN 207 (wmi_resmgr_set_chan_time_quota_cmd_fixed_param)); 208 cmdTQ->num_chans = num_channels; 209 210 /* Update channel time quota information for home channel(s) */ 211 buf_ptr += sizeof(*cmdTQ); 212 WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, 213 num_channels * sizeof(wmi_resmgr_chan_time_quota)); 214 buf_ptr += WMI_TLV_HDR_SIZE; 215 chan_quota.chan_mhz = chan1_freq; 216 chan_quota.channel_time_quota = quota_chan1; 217 qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); 218 /* Construct channel and quota record for the 2nd MCC mode. */ 219 buf_ptr += sizeof(chan_quota); 220 chan_quota.chan_mhz = chan2_freq; 221 chan_quota.channel_time_quota = quota_chan2; 222 qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); 223 224 wmi_mtrace(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, NO_SESSION, 0); 225 ret = wmi_unified_cmd_send(wmi_handle, buf, len, 226 WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); 227 if (QDF_IS_STATUS_ERROR(ret)) { 228 wmi_err("Failed to send MCC Channel Time Quota command"); 229 wmi_buf_free(buf); 230 QDF_ASSERT(0); 231 } 232 233 return ret; 234 } 235 236 #ifdef WLAN_FEATURE_MCC_QUOTA 237 /** 238 * convert_to_host_quota_type() - convert wmi quota type to host quota type 239 * @quota_type: wmi target quota type 240 * 241 * Return: enum mcc_quota_type 242 */ 243 static enum mcc_quota_type convert_to_host_quota_type(uint32_t quota_type) 244 { 245 switch (quota_type) { 246 case WMI_RESMGR_QUOTA_TYPE_CLEAR: 247 return QUOTA_TYPE_CLEAR; 248 case WMI_RESMGR_QUOTA_TYPE_FIXED: 249 return QUOTA_TYPE_FIXED; 250 case WMI_RESMGR_QUOTA_TYPE_DYNAMIC: 251 return QUOTA_TYPE_DYNAMIC; 252 default: 253 wmi_err("mcc quota unknown quota type %d", quota_type); 254 return QUOTA_TYPE_UNKNOWN; 255 } 256 } 257 258 /** 259 * extract_mcc_quota_ev_param_tlv() - extract mcc quota information from wmi 260 * event 261 * @wmi_handle: wmi handle 262 * @param evt_buf: pointer to event buffer 263 * @param param: Pointer to hold mcc quota info 264 * 265 * Return: QDF_STATUS_SUCCESS for success or error code 266 */ 267 static QDF_STATUS 268 extract_mcc_quota_ev_param_tlv(wmi_unified_t wmi_handle, 269 void *evt_buf, struct mcc_quota_info *param) 270 { 271 WMI_RESMGR_CHAN_TIME_QUOTA_CHANGED_EVENTID_param_tlvs *param_tlvs; 272 wmi_resmgr_chan_time_quota_changed_event_fixed_param *fixed_param; 273 uint8_t i; 274 wmi_resmgr_chan_time_quota_tlv *wmi_mcc_quota_info; 275 276 if (!param) { 277 wmi_err("mcc quota information param is null"); 278 return QDF_STATUS_E_INVAL; 279 } 280 281 param_tlvs = evt_buf; 282 if (!param_tlvs || !param_tlvs->fixed_param) { 283 wmi_err("Invalid mcc quota event buffer"); 284 return QDF_STATUS_E_INVAL; 285 } 286 fixed_param = param_tlvs->fixed_param; 287 288 wmi_debug("mcc quota type %d, num %d", 289 fixed_param->quota_type, param_tlvs->num_chan_quota); 290 291 param->type = convert_to_host_quota_type(fixed_param->quota_type); 292 if (param->type == QUOTA_TYPE_UNKNOWN) 293 return QDF_STATUS_E_INVAL; 294 295 if (!param_tlvs->chan_quota) { 296 param->num_chan_quota = 0; 297 return QDF_STATUS_SUCCESS; 298 } 299 300 if (param_tlvs->num_chan_quota > MAX_MCC_QUOTA_CH_NUM) 301 wmi_warn("mcc quota num %d unexpected", 302 param_tlvs->num_chan_quota); 303 param->num_chan_quota = qdf_min(param_tlvs->num_chan_quota, 304 (uint32_t)MAX_MCC_QUOTA_CH_NUM); 305 wmi_mcc_quota_info = param_tlvs->chan_quota; 306 for (i = 0; i < param->num_chan_quota; i++) { 307 param->chan_quota[i].chan_mhz = 308 wmi_mcc_quota_info[i].chan_time_quota.chan_mhz; 309 param->chan_quota[i].channel_time_quota = 310 wmi_mcc_quota_info[i].chan_time_quota.channel_time_quota; 311 wmi_debug("mcc quota [%d] chan %d, quota %d", 312 i, param->chan_quota[i].chan_mhz, 313 param->chan_quota[i].channel_time_quota); 314 } 315 316 return QDF_STATUS_SUCCESS; 317 } 318 319 static void wmi_mcc_quota_evt_attach_tlv(wmi_unified_t wmi_handle) 320 { 321 struct wmi_ops *ops = wmi_handle->ops; 322 323 ops->extract_mcc_quota_ev_param = extract_mcc_quota_ev_param_tlv; 324 } 325 #else 326 static inline void wmi_mcc_quota_evt_attach_tlv(wmi_unified_t wmi_handle) 327 { 328 } 329 #endif 330 331 void wmi_concurrency_attach_tlv(wmi_unified_t wmi_handle) 332 { 333 struct wmi_ops *ops = wmi_handle->ops; 334 335 ops->send_set_enable_disable_mcc_adaptive_scheduler_cmd = 336 send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv; 337 ops->send_set_mcc_channel_time_latency_cmd = 338 send_set_mcc_channel_time_latency_cmd_tlv; 339 ops->send_set_mcc_channel_time_quota_cmd = 340 send_set_mcc_channel_time_quota_cmd_tlv; 341 wmi_mcc_quota_evt_attach_tlv(wmi_handle); 342 } 343