1 /*
2 * Copyright (c) 2012-2021 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 "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
sch_set_beacon_interval(struct mac_context * mac,struct pe_session * pe_session)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
sch_edca_profile_update_all(struct mac_context * pmac)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
sch_get_params(struct mac_context * mac,uint32_t params[][CFG_EDCA_DATA_LEN],uint8_t local)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
broadcast_wmm_of_concurrent_sta_session(struct mac_context * mac_ctx,struct pe_session * session)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
sch_qos_update_broadcast(struct mac_context * mac,struct pe_session * pe_session)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
sch_qos_update_local(struct mac_context * mac,struct pe_session * pe_session)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 */
sch_set_default_edca_params(struct mac_context * mac,struct pe_session * pe_session)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
set_sch_edca_params(struct mac_context * mac,uint32_t params[][CFG_EDCA_DATA_LEN],struct pe_session * pe_session)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
get_wmm_local_params(struct mac_context * mac_ctx,uint32_t params[][CFG_EDCA_DATA_LEN])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 */
sch_qos_concurrency_update(void)506 void sch_qos_concurrency_update(void)
507 {
508 lim_send_conc_params_update();
509 }
510
sch_qos_update_edca_pifs_param_for_ll_sap(struct mac_context * mac,uint8_t vdev_id)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 */
sch_edca_profile_update(struct mac_context * mac,struct pe_session * pe_session)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_vdev_ll_lt_sap(
540 mac->psoc, pe_session->vdev_id))
541 sch_qos_update_edca_pifs_param_for_ll_sap(
542 mac,
543 pe_session->vdev_id);
544 }
545 }
546
547 /* -------------------------------------------------------------------- */
548