1 /* 2 * Copyright (c) 2012-2021 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 "cds_api.h" 21 #include "sir_common.h" 22 23 #include "wni_cfg.h" 24 #include "ani_global.h" 25 #include "lim_api.h" 26 #include "lim_send_messages.h" 27 28 #include "sch_api.h" 29 #include "wlan_mlme_api.h" 30 #include <wlan_reg_services_api.h> 31 #include "lim_utils.h" 32 33 /* / Minimum beacon interval allowed (in Kus) */ 34 #define SCH_BEACON_INTERVAL_MIN 10 35 36 /* / Maximum beacon interval allowed (in Kus) */ 37 #define SCH_BEACON_INTERVAL_MAX 10000 38 39 /* / convert the CW values into a uint16_t */ 40 #define GET_CW(pCw) ((uint16_t) ((*(pCw) << 8) + *((pCw) + 1))) 41 42 /* Max debug string size for WMM in bytes */ 43 #define SCH_WMM_DEBUG_STRING_SIZE 512 44 45 /* local functions */ 46 static QDF_STATUS 47 get_wmm_local_params(struct mac_context *mac, 48 uint32_t params[][CFG_EDCA_DATA_LEN]); 49 static void 50 set_sch_edca_params(struct mac_context *mac, 51 uint32_t params[][CFG_EDCA_DATA_LEN], 52 struct pe_session *pe_session); 53 54 /* -------------------------------------------------------------------- */ 55 /** 56 * sch_set_beacon_interval 57 * 58 * FUNCTION: 59 * 60 * LOGIC: 61 * 62 * ASSUMPTIONS: 63 * 64 * NOTE: 65 * 66 * @param None 67 * @return None 68 */ 69 70 void sch_set_beacon_interval(struct mac_context *mac, 71 struct pe_session *pe_session) 72 { 73 uint32_t bi; 74 75 bi = pe_session->beaconParams.beaconInterval; 76 77 if (bi < SCH_BEACON_INTERVAL_MIN || bi > SCH_BEACON_INTERVAL_MAX) { 78 pe_debug("Invalid beacon interval %d (should be [%d,%d]", bi, 79 SCH_BEACON_INTERVAL_MIN, SCH_BEACON_INTERVAL_MAX); 80 return; 81 } 82 83 mac->sch.beacon_interval = (uint16_t) bi; 84 } 85 86 void sch_edca_profile_update_all(struct mac_context *pmac) 87 { 88 uint32_t i; 89 struct pe_session *psession_entry; 90 91 for (i = 0; i < pmac->lim.maxBssId; i++) { 92 psession_entry = &pmac->lim.gpSession[i]; 93 if (psession_entry->valid) 94 sch_edca_profile_update(pmac, psession_entry); 95 } 96 } 97 98 /** 99 * sch_get_params() - get the local or broadcast parameters based on the profile 100 * specified in the config params are delivered in this order: BE, BK, VI, VO 101 */ 102 static QDF_STATUS 103 sch_get_params(struct mac_context *mac, 104 uint32_t params[][CFG_EDCA_DATA_LEN], 105 uint8_t local) 106 { 107 uint32_t val; 108 uint32_t i, idx; 109 uint32_t *prf; 110 struct wlan_mlme_edca_params *edca_params; 111 QDF_STATUS status; 112 uint8_t country_code_str[REG_ALPHA2_LEN + 1]; 113 uint32_t ani_l[] = {edca_ani_acbe_local, edca_ani_acbk_local, 114 edca_ani_acvi_local, edca_ani_acvo_local}; 115 116 uint32_t wme_l[] = {edca_wme_acbe_local, edca_wme_acbk_local, 117 edca_wme_acvi_local, edca_wme_acvo_local}; 118 119 uint32_t etsi_l[] = {edca_etsi_acbe_local, edca_etsi_acbk_local, 120 edca_etsi_acvi_local, edca_etsi_acvo_local}; 121 122 uint32_t ani_b[] = {edca_ani_acbe_bcast, edca_ani_acbk_bcast, 123 edca_ani_acvi_bcast, edca_ani_acvo_bcast}; 124 125 uint32_t wme_b[] = {edca_wme_acbe_bcast, edca_wme_acbk_bcast, 126 edca_wme_acvi_bcast, edca_wme_acvo_bcast}; 127 128 uint32_t etsi_b[] = {edca_etsi_acbe_bcast, edca_etsi_acbk_bcast, 129 edca_etsi_acvi_bcast, edca_etsi_acvo_bcast}; 130 edca_params = &mac->mlme_cfg->edca_params; 131 132 wlan_reg_get_cc_and_src(mac->psoc, country_code_str); 133 134 if (cds_is_etsi_europe_country(country_code_str)) { 135 val = WNI_CFG_EDCA_PROFILE_ETSI_EUROPE; 136 pe_debug("switch to ETSI EUROPE profile country code %c%c", 137 country_code_str[0], country_code_str[1]); 138 } else { 139 val = mac->mlme_cfg->wmm_params.edca_profile; 140 } 141 if (val >= WNI_CFG_EDCA_PROFILE_MAX) { 142 pe_warn("Invalid EDCA_PROFILE %d, using %d instead", val, 143 WNI_CFG_EDCA_PROFILE_ANI); 144 val = WNI_CFG_EDCA_PROFILE_ANI; 145 } 146 147 pe_debug("EdcaProfile: Using %d (%s)", val, 148 ((val == WNI_CFG_EDCA_PROFILE_WMM) ? "WMM" : "HiPerf")); 149 150 if (local) { 151 switch (val) { 152 case WNI_CFG_EDCA_PROFILE_WMM: 153 prf = &wme_l[0]; 154 break; 155 case WNI_CFG_EDCA_PROFILE_ETSI_EUROPE: 156 prf = &etsi_l[0]; 157 break; 158 case WNI_CFG_EDCA_PROFILE_ANI: 159 default: 160 prf = &ani_l[0]; 161 break; 162 } 163 } else { 164 switch (val) { 165 case WNI_CFG_EDCA_PROFILE_WMM: 166 prf = &wme_b[0]; 167 break; 168 case WNI_CFG_EDCA_PROFILE_ETSI_EUROPE: 169 prf = &etsi_b[0]; 170 break; 171 case WNI_CFG_EDCA_PROFILE_ANI: 172 default: 173 prf = &ani_b[0]; 174 break; 175 } 176 } 177 178 for (i = 0; i < 4; i++) { 179 uint8_t data[CFG_EDCA_DATA_LEN]; 180 181 status = wlan_mlme_get_edca_params(edca_params, 182 (uint8_t *)&data[0], 183 (uint8_t)prf[i]); 184 if (QDF_IS_STATUS_ERROR(status)) { 185 pe_err("Get failed for ac:%d", i); 186 return QDF_STATUS_E_FAILURE; 187 } 188 189 for (idx = 0; idx < CFG_EDCA_DATA_LEN; idx++) 190 params[i][idx] = (uint32_t) data[idx]; 191 } 192 pe_debug("GetParams: local=%d, profile = %d Done", local, val); 193 194 return QDF_STATUS_SUCCESS; 195 } 196 197 /** 198 * broadcast_wmm_of_concurrent_sta_session() - broadcasts wmm info 199 * @mac_ctx: mac global context 200 * @session: pesession entry 201 * 202 * Return: true if wmm param updated, false if wmm param not updated 203 */ 204 static bool 205 broadcast_wmm_of_concurrent_sta_session(struct mac_context *mac_ctx, 206 struct pe_session *session) 207 { 208 uint8_t i, j; 209 struct pe_session *concurrent_session = NULL; 210 211 for (i = 0; i < mac_ctx->lim.maxBssId; i++) { 212 /* 213 * Find another INFRA STA AP session on same operating channel. 214 * The session entry passed to this API is for GO/SoftAP session 215 * that is getting added currently 216 */ 217 if (!((mac_ctx->lim.gpSession[i].valid == true) && 218 (mac_ctx->lim.gpSession[i].peSessionId != 219 session->peSessionId) && 220 (mac_ctx->lim.gpSession[i].curr_op_freq == 221 session->curr_op_freq) && 222 (mac_ctx->lim.gpSession[i].limSystemRole == 223 eLIM_STA_ROLE))) 224 continue; 225 226 concurrent_session = &(mac_ctx->lim.gpSession[i]); 227 break; 228 } 229 230 if (!concurrent_session) 231 return false; 232 233 if (!qdf_mem_cmp(session->gLimEdcaParamsBC, 234 concurrent_session->gLimEdcaParams, 235 sizeof(concurrent_session->gLimEdcaParams))) 236 return false; 237 238 /* 239 * Once atleast one concurrent session on same channel is found and WMM 240 * broadcast params for current SoftAP/GO session updated, return 241 */ 242 for (j = 0; j < QCA_WLAN_AC_ALL; j++) { 243 session->gLimEdcaParamsBC[j].aci.acm = 244 concurrent_session->gLimEdcaParams[j].aci.acm; 245 session->gLimEdcaParamsBC[j].aci.aifsn = 246 concurrent_session->gLimEdcaParams[j].aci.aifsn; 247 session->gLimEdcaParamsBC[j].cw.min = 248 concurrent_session->gLimEdcaParams[j].cw.min; 249 session->gLimEdcaParamsBC[j].cw.max = 250 concurrent_session->gLimEdcaParams[j].cw.max; 251 session->gLimEdcaParamsBC[j].txoplimit = 252 concurrent_session->gLimEdcaParams[j].txoplimit; 253 pe_debug("QoSUpdateBCast changed again due to concurrent INFRA STA session: AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", 254 j, session->gLimEdcaParamsBC[j].aci.aifsn, 255 session->gLimEdcaParamsBC[j].aci.acm, 256 session->gLimEdcaParamsBC[j].cw.min, 257 session->gLimEdcaParamsBC[j].cw.max, 258 session->gLimEdcaParamsBC[j].txoplimit); 259 } 260 return true; 261 } 262 263 void sch_qos_update_broadcast(struct mac_context *mac, struct pe_session *pe_session) 264 { 265 uint32_t params[4][CFG_EDCA_DATA_LEN]; 266 uint32_t cwminidx, cwmaxidx, txopidx; 267 uint32_t phyMode; 268 uint8_t i; 269 bool updated = false; 270 QDF_STATUS status; 271 uint8_t *debug_str; 272 uint32_t len = 0; 273 274 if (sch_get_params(mac, params, false) != QDF_STATUS_SUCCESS) { 275 pe_debug("QosUpdateBroadcast: failed"); 276 return; 277 } 278 lim_get_phy_mode(mac, &phyMode, pe_session); 279 280 if (phyMode == WNI_CFG_PHY_MODE_11G) { 281 cwminidx = CFG_EDCA_PROFILE_CWMING_IDX; 282 cwmaxidx = CFG_EDCA_PROFILE_CWMAXG_IDX; 283 txopidx = CFG_EDCA_PROFILE_TXOPG_IDX; 284 } else if (phyMode == WNI_CFG_PHY_MODE_11B) { 285 cwminidx = CFG_EDCA_PROFILE_CWMINB_IDX; 286 cwmaxidx = CFG_EDCA_PROFILE_CWMAXB_IDX; 287 txopidx = CFG_EDCA_PROFILE_TXOPB_IDX; 288 } else { 289 /* This can happen if mode is not set yet, assume 11a mode */ 290 cwminidx = CFG_EDCA_PROFILE_CWMINA_IDX; 291 cwmaxidx = CFG_EDCA_PROFILE_CWMAXA_IDX; 292 txopidx = CFG_EDCA_PROFILE_TXOPA_IDX; 293 } 294 295 debug_str = qdf_mem_malloc(SCH_WMM_DEBUG_STRING_SIZE); 296 if (!debug_str) 297 return; 298 299 for (i = 0; i < QCA_WLAN_AC_ALL; i++) { 300 if (pe_session->gLimEdcaParamsBC[i].aci.acm != 301 (uint8_t)params[i][CFG_EDCA_PROFILE_ACM_IDX]) { 302 pe_session->gLimEdcaParamsBC[i].aci.acm = 303 (uint8_t)params[i][CFG_EDCA_PROFILE_ACM_IDX]; 304 updated = true; 305 } 306 if (pe_session->gLimEdcaParamsBC[i].aci.aifsn != 307 (uint8_t)params[i][CFG_EDCA_PROFILE_AIFSN_IDX]) { 308 pe_session->gLimEdcaParamsBC[i].aci.aifsn = 309 (uint8_t)params[i][CFG_EDCA_PROFILE_AIFSN_IDX]; 310 updated = true; 311 } 312 if (pe_session->gLimEdcaParamsBC[i].cw.min != 313 convert_cw(GET_CW(¶ms[i][cwminidx]))) { 314 pe_session->gLimEdcaParamsBC[i].cw.min = 315 convert_cw(GET_CW(¶ms[i][cwminidx])); 316 updated = true; 317 } 318 if (pe_session->gLimEdcaParamsBC[i].cw.max != 319 convert_cw(GET_CW(¶ms[i][cwmaxidx]))) { 320 pe_session->gLimEdcaParamsBC[i].cw.max = 321 convert_cw(GET_CW(¶ms[i][cwmaxidx])); 322 updated = true; 323 } 324 if (pe_session->gLimEdcaParamsBC[i].txoplimit != 325 (uint16_t)params[i][txopidx]) { 326 pe_session->gLimEdcaParamsBC[i].txoplimit = 327 (uint16_t)params[i][txopidx]; 328 updated = true; 329 } 330 331 len += qdf_scnprintf(debug_str + len, 332 SCH_WMM_DEBUG_STRING_SIZE - len, 333 "AC[%d]: AIFSN %d ACM %d CWmin %d CWmax %d TxOp %d, ", 334 i, pe_session->gLimEdcaParamsBC[i].aci.aifsn, 335 pe_session->gLimEdcaParamsBC[i].aci.acm, 336 pe_session->gLimEdcaParamsBC[i].cw.min, 337 pe_session->gLimEdcaParamsBC[i].cw.max, 338 pe_session->gLimEdcaParamsBC[i].txoplimit); 339 340 } 341 342 pe_nofl_debug("QosUpdBcast: mode %d, %s", phyMode, debug_str); 343 qdf_mem_free(debug_str); 344 345 /* 346 * If there exists a concurrent STA-AP session, use its WMM 347 * params to broadcast in beacons. WFA Wifi Direct test plan 348 * 6.1.14 requirement 349 */ 350 if (broadcast_wmm_of_concurrent_sta_session(mac, pe_session)) 351 updated = true; 352 if (updated) 353 pe_session->gLimEdcaParamSetCount++; 354 355 status = sch_set_fixed_beacon_fields(mac, pe_session); 356 if (QDF_IS_STATUS_ERROR(status)) 357 pe_err("Unable to set beacon fields!"); 358 } 359 360 void sch_qos_update_local(struct mac_context *mac, struct pe_session *pe_session) 361 { 362 363 uint32_t params[4][CFG_EDCA_DATA_LEN]; 364 QDF_STATUS status; 365 366 pe_debug("user_edca_set : %u", pe_session->user_edca_set); 367 /* If user preferred EDCA setting present, use it, do not default */ 368 if (pe_session->user_edca_set == 0) { 369 status = sch_get_params(mac, params, true /*local */); 370 if (QDF_IS_STATUS_ERROR(status)) { 371 pe_err("sch_get_params(local) failed"); 372 return; 373 } 374 375 set_sch_edca_params(mac, params, pe_session); 376 } 377 378 lim_set_active_edca_params(mac, pe_session->gLimEdcaParams, pe_session); 379 380 /* For AP, the bssID is stored in LIM Global context. */ 381 lim_send_edca_params(mac, pe_session->gLimEdcaParamsActive, 382 pe_session->vdev_id, false); 383 } 384 385 /** 386 * sch_set_default_edca_params() - This function sets the gLimEdcaParams to the 387 * default local wmm profile. 388 * @mac - Global mac context 389 * @pe_session - PE session 390 * 391 * return none 392 */ 393 void sch_set_default_edca_params(struct mac_context *mac, struct pe_session *pe_session) 394 { 395 uint32_t params[4][CFG_EDCA_DATA_LEN]; 396 397 if (get_wmm_local_params(mac, params) != QDF_STATUS_SUCCESS) { 398 pe_err("get_wmm_local_params() failed"); 399 return; 400 } 401 402 set_sch_edca_params(mac, params, pe_session); 403 return; 404 } 405 406 /** 407 * set_sch_edca_params() - This function fills in the gLimEdcaParams structure 408 * with the given edca params. 409 * @mac - global mac context 410 * @pe_session - PE session 411 * @params - EDCA parameters 412 * 413 * Return none 414 */ 415 static void 416 set_sch_edca_params(struct mac_context *mac, 417 uint32_t params[][CFG_EDCA_DATA_LEN], 418 struct pe_session *pe_session) 419 { 420 uint32_t i; 421 uint32_t cwminidx, cwmaxidx, txopidx; 422 uint32_t phyMode; 423 424 lim_get_phy_mode(mac, &phyMode, pe_session); 425 426 /* if (mac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11G) */ 427 if (phyMode == WNI_CFG_PHY_MODE_11G) { 428 cwminidx = CFG_EDCA_PROFILE_CWMING_IDX; 429 cwmaxidx = CFG_EDCA_PROFILE_CWMAXG_IDX; 430 txopidx = CFG_EDCA_PROFILE_TXOPG_IDX; 431 } 432 /* else if (mac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11B) */ 433 else if (phyMode == WNI_CFG_PHY_MODE_11B) { 434 cwminidx = CFG_EDCA_PROFILE_CWMINB_IDX; 435 cwmaxidx = CFG_EDCA_PROFILE_CWMAXB_IDX; 436 txopidx = CFG_EDCA_PROFILE_TXOPB_IDX; 437 } else { 438 /* This can happen if mode is not set yet, assume 11a mode */ 439 cwminidx = CFG_EDCA_PROFILE_CWMINA_IDX; 440 cwmaxidx = CFG_EDCA_PROFILE_CWMAXA_IDX; 441 txopidx = CFG_EDCA_PROFILE_TXOPA_IDX; 442 } 443 444 for (i = 0; i < QCA_WLAN_AC_ALL; i++) { 445 pe_session->gLimEdcaParams[i].aci.acm = 446 (uint8_t)params[i][CFG_EDCA_PROFILE_ACM_IDX]; 447 pe_session->gLimEdcaParams[i].aci.aifsn = 448 (uint8_t)params[i][CFG_EDCA_PROFILE_AIFSN_IDX]; 449 pe_session->gLimEdcaParams[i].cw.min = 450 convert_cw(GET_CW(¶ms[i][cwminidx])); 451 pe_session->gLimEdcaParams[i].cw.max = 452 convert_cw(GET_CW(¶ms[i][cwmaxidx])); 453 pe_session->gLimEdcaParams[i].txoplimit = 454 (uint16_t)params[i][txopidx]; 455 } 456 return; 457 } 458 459 /** 460 * get_wmm_local_params() - This function gets the WMM local edca parameters. 461 * @mac 462 * @params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN] 463 * 464 * Return none 465 */ 466 static QDF_STATUS 467 get_wmm_local_params(struct mac_context *mac_ctx, 468 uint32_t params[][CFG_EDCA_DATA_LEN]) 469 { 470 uint32_t i, idx; 471 QDF_STATUS status; 472 struct wlan_mlme_edca_params *edca_params; 473 uint32_t wme_l[] = {edca_wme_acbe_local, edca_wme_acbk_local, 474 edca_wme_acvi_local, edca_wme_acvo_local}; 475 476 if (!mac_ctx->mlme_cfg) { 477 pe_err("NULL mlme cfg"); 478 return QDF_STATUS_E_FAILURE; 479 } 480 481 edca_params = &mac_ctx->mlme_cfg->edca_params; 482 for (i = 0; i < 4; i++) { 483 uint8_t data[CFG_EDCA_DATA_LEN]; 484 485 status = wlan_mlme_get_edca_params(edca_params, 486 (uint8_t *)&data[0], 487 (uint8_t)wme_l[i]); 488 if (QDF_IS_STATUS_ERROR(status)) { 489 pe_err("Get failed for ac:[%d]", i); 490 return QDF_STATUS_E_FAILURE; 491 } 492 for (idx = 0; idx < CFG_EDCA_DATA_LEN; idx++) 493 params[i][idx] = (uint32_t) data[idx]; 494 } 495 return QDF_STATUS_SUCCESS; 496 } 497 498 /** 499 * sch_qos_concurrency_update() - This function updates the local and 500 * broadcast based on STA and SAP 501 * concurrency. It also updates the 502 * edcaParamSetCount, if Broadcast EDCA params are updated based on Concurrency. 503 * 504 * Return none 505 */ 506 void sch_qos_concurrency_update(void) 507 { 508 lim_send_conc_params_update(); 509 } 510 511 static void sch_qos_update_edca_pifs_param_for_ll_sap(struct mac_context *mac, 512 uint8_t vdev_id) 513 { 514 struct wlan_edca_pifs_param_ie param = {0}; 515 enum host_edca_param_type edca_param_type = 516 HOST_EDCA_PARAM_TYPE_AGGRESSIVE; 517 518 edca_param_type = mac->mlme_cfg->edca_params.edca_param_type; 519 wlan_mlme_set_edca_pifs_param(¶m, edca_param_type); 520 lim_send_edca_pifs_param(mac, ¶m, vdev_id); 521 } 522 523 /** 524 * sch_edca_profile_update() - This function updates the local and broadcast 525 * EDCA params in the gLimEdcaParams structure. It also updates the 526 * edcaParamSetCount. 527 * 528 * @mac - global mac context 529 * 530 * Return none 531 */ 532 void sch_edca_profile_update(struct mac_context *mac, struct pe_session *pe_session) 533 { 534 if (LIM_IS_AP_ROLE(pe_session)) { 535 sch_qos_update_local(mac, pe_session); 536 sch_qos_update_broadcast(mac, pe_session); 537 sch_qos_concurrency_update(); 538 539 if (policy_mgr_is_ll_sap_present( 540 mac->psoc, 541 policy_mgr_convert_device_mode_to_qdf_type( 542 pe_session->opmode), pe_session->vdev_id)) 543 sch_qos_update_edca_pifs_param_for_ll_sap( 544 mac, 545 pe_session->vdev_id); 546 } 547 } 548 549 /* -------------------------------------------------------------------- */ 550