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