1 /*
2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2024 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 /**
21 * DOC: wlan_hdd_cfg.c
22 *
23 * WLAN Host Device Driver configuration interface implementation
24 */
25
26 /* Include Files */
27
28 #include <linux/firmware.h>
29 #include <linux/string.h>
30 #include <wlan_hdd_includes.h>
31 #include <wlan_hdd_main.h>
32 #include <wlan_hdd_assoc.h>
33 #include <wlan_hdd_cfg.h>
34 #include <linux/string.h>
35 #include <qdf_types.h>
36 #include <csr_api.h>
37 #include <wlan_hdd_misc.h>
38 #include <wlan_hdd_napi.h>
39 #include <cds_api.h>
40 #include <wlan_hdd_regulatory.h>
41 #include "wlan_hdd_he.h"
42 #include <wlan_policy_mgr_api.h>
43 #include "wifi_pos_api.h"
44 #include "wlan_hdd_green_ap.h"
45 #include "wlan_hdd_twt.h"
46 #include "wlan_policy_mgr_ucfg.h"
47 #include "wlan_mlme_ucfg_api.h"
48 #include "wlan_mlme_public_struct.h"
49 #include "wlan_fwol_ucfg_api.h"
50 #include "cfg_ucfg_api.h"
51 #include "hdd_dp_cfg.h"
52 #include <wma_api.h>
53 #include "wlan_hdd_object_manager.h"
54 #include "wlan_dp_ucfg_api.h"
55 #include "wlan_cmn.h"
56
57 #ifndef WLAN_MAC_ADDR_UPDATE_DISABLE
58 /**
59 * get_next_line() - find and locate the new line pointer
60 * @str: pointer to string
61 *
62 * This function returns a pointer to the character after the occurrence
63 * of a new line character. It also modifies the original string by replacing
64 * the '\n' character with the null character.
65 *
66 * Return: the pointer to the character at new line,
67 * or NULL if no new line character was found
68 */
get_next_line(char * str)69 static char *get_next_line(char *str)
70 {
71 char c;
72
73 if (!str || *str == '\0')
74 return NULL;
75
76 c = *str;
77 while (c != '\n' && c != '\0' && c != 0xd) {
78 str = str + 1;
79 c = *str;
80 }
81
82 if (c == '\0')
83 return NULL;
84
85 *str = '\0';
86 return str + 1;
87 }
88
89 /** look for space. Ascii values to look are
90 * 0x09 == horizontal tab
91 * 0x0a == Newline ("\n")
92 * 0x0b == vertical tab
93 * 0x0c == Newpage or feed form.
94 * 0x0d == carriage return (CR or "\r")
95 * Null ('\0') should not considered as space.
96 */
97 #define i_isspace(ch) (((ch) >= 0x09 && (ch) <= 0x0d) || (ch) == ' ')
98
99 /**
100 * i_trim() - trims any leading and trailing white spaces
101 * @str: pointer to string
102 *
103 * Return: the pointer of the string
104 */
i_trim(char * str)105 static char *i_trim(char *str)
106 {
107 char *ptr;
108
109 if (*str == '\0')
110 return str;
111
112 /* Find the first non white-space */
113 ptr = str;
114 while (i_isspace(*ptr))
115 ptr++;
116
117 if (*ptr == '\0')
118 return str;
119
120 /* This is the new start of the string */
121 str = ptr;
122
123 /* Find the last non white-space */
124 ptr += strlen(ptr) - 1;
125
126 while (ptr != str && i_isspace(*ptr))
127 ptr--;
128
129 /* Null terminate the following character */
130 ptr[1] = '\0';
131
132 return str;
133 }
134
135 /** struct hdd_cfg_entry - ini configuration entry
136 * @name: name of the entry
137 * @value: value of the entry
138 */
139 struct hdd_cfg_entry {
140 char *name;
141 char *value;
142 };
143
144 /**
145 * update_mac_from_string() - convert string to 6 bytes mac address
146 * @hdd_ctx: the pointer to hdd context
147 * @mac_table: the mac_table to carry the conversion
148 * @num: number of the interface
149 *
150 * 00AA00BB00CC -> 0x00 0xAA 0x00 0xBB 0x00 0xCC
151 *
152 * Return: QDF_STATUS
153 */
update_mac_from_string(struct hdd_context * hdd_ctx,struct hdd_cfg_entry * mac_table,int num)154 static QDF_STATUS update_mac_from_string(struct hdd_context *hdd_ctx,
155 struct hdd_cfg_entry *mac_table,
156 int num)
157 {
158 int i = 0, j = 0, res = 0;
159 char *candidate = NULL;
160 struct qdf_mac_addr macaddr[QDF_MAX_CONCURRENCY_PERSONA];
161 QDF_STATUS status = QDF_STATUS_SUCCESS;
162
163 memset(macaddr, 0, sizeof(macaddr));
164
165 for (i = 0; i < num; i++) {
166 candidate = mac_table[i].value;
167 for (j = 0; j < QDF_MAC_ADDR_SIZE; j++) {
168 res =
169 hex2bin(&macaddr[i].bytes[j], &candidate[(j << 1)],
170 1);
171 if (res < 0)
172 break;
173 }
174 if (res == 0 && !qdf_is_macaddr_zero(&macaddr[i])) {
175 qdf_mem_copy((uint8_t *)&hdd_ctx->
176 provisioned_mac_addr[i].bytes[0],
177 (uint8_t *) &macaddr[i].bytes[0],
178 QDF_MAC_ADDR_SIZE);
179 } else {
180 status = QDF_STATUS_E_FAILURE;
181 break;
182 }
183 }
184 return status;
185 }
186
187 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0))
188 static inline
hdd_firmware_request_nowarn(const struct firmware ** fw,const char * name,struct device * device)189 int hdd_firmware_request_nowarn(const struct firmware **fw,
190 const char *name,
191 struct device *device)
192 {
193 return firmware_request_nowarn(fw, name, device);
194 }
195 #else
196 static inline
hdd_firmware_request_nowarn(const struct firmware ** fw,const char * name,struct device * device)197 int hdd_firmware_request_nowarn(const struct firmware **fw,
198 const char *name,
199 struct device *device)
200 {
201 return request_firmware(fw, name, device);
202 }
203 #endif
204
205 /**
206 * hdd_update_mac_config() - update MAC address from cfg file
207 * @hdd_ctx: the pointer to hdd context
208 *
209 * It overwrites the MAC address if config file exist.
210 *
211 * Return: QDF_STATUS_SUCCESS if the MAC address is found from cfg file
212 * and overwritten, otherwise QDF_STATUS_E_INVAL
213 */
hdd_update_mac_config(struct hdd_context * hdd_ctx)214 QDF_STATUS hdd_update_mac_config(struct hdd_context *hdd_ctx)
215 {
216 int status, i = 0;
217 const struct firmware *fw = NULL;
218 char *line, *buffer = NULL;
219 char *temp = NULL;
220 char *name, *value;
221 int max_mac_addr = QDF_MAX_CONCURRENCY_PERSONA;
222 struct hdd_cfg_entry mac_table[QDF_MAX_CONCURRENCY_PERSONA];
223 struct qdf_mac_addr custom_mac_addr;
224
225 QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
226
227 if (!hdd_ctx->config->read_mac_addr_from_mac_file) {
228 hdd_debug("Reading MAC address from MAC file is not enabled.");
229 return QDF_STATUS_E_FAILURE;
230 }
231
232 memset(mac_table, 0, sizeof(mac_table));
233 status = hdd_firmware_request_nowarn(&fw, WLAN_MAC_FILE,
234 hdd_ctx->parent_dev);
235 if (status) {
236 /*
237 * request_firmware "fails" if the file is not found, which is a
238 * valid setup for us, so log using debug instead of error
239 */
240 hdd_debug("request_firmware failed; status:%d", status);
241 return QDF_STATUS_E_FAILURE;
242 }
243
244 if (!fw || !fw->data || !fw->size) {
245 hdd_alert("invalid firmware");
246 qdf_status = QDF_STATUS_E_INVAL;
247 goto config_exit;
248 }
249
250 hdd_debug("wlan_mac.bin size %zu", fw->size);
251
252 temp = qdf_mem_malloc(fw->size + 1);
253 if (!temp) {
254 qdf_status = QDF_STATUS_E_NOMEM;
255 goto config_exit;
256 }
257 buffer = temp;
258 qdf_mem_copy(buffer, fw->data, fw->size);
259 buffer[fw->size] = 0x0;
260
261 /* data format:
262 * Intf0MacAddress=00AA00BB00CC
263 * Intf1MacAddress=00AA00BB00CD
264 * END
265 */
266 while (buffer) {
267 line = get_next_line(buffer);
268 buffer = i_trim(buffer);
269
270 if (strlen((char *)buffer) == 0 || *buffer == '#') {
271 buffer = line;
272 continue;
273 }
274 if (strncmp(buffer, "END", 3) == 0)
275 break;
276
277 name = buffer;
278 buffer = strnchr(buffer, strlen(buffer), '=');
279 if (buffer) {
280 *buffer++ = '\0';
281 i_trim(name);
282 if (strlen(name) != 0) {
283 buffer = i_trim(buffer);
284 if (strlen(buffer) == 12) {
285 value = buffer;
286 mac_table[i].name = name;
287 mac_table[i++].value = value;
288 if (i >= QDF_MAX_CONCURRENCY_PERSONA)
289 break;
290 }
291 }
292 }
293 buffer = line;
294 }
295
296 if (i != 0 && i <= QDF_MAX_CONCURRENCY_PERSONA) {
297 hdd_debug("%d Mac addresses provided", i);
298 } else {
299 hdd_err("invalid number of Mac address provided, nMac = %d", i);
300 qdf_status = QDF_STATUS_E_INVAL;
301 goto config_exit;
302 }
303
304 qdf_status = update_mac_from_string(hdd_ctx, &mac_table[0], i);
305 if (QDF_IS_STATUS_ERROR(qdf_status)) {
306 hdd_err("Invalid MAC addresses provided");
307 goto config_exit;
308 }
309 hdd_ctx->num_provisioned_addr = i;
310 hdd_debug("Populating remaining %d Mac addresses",
311 max_mac_addr - i);
312 hdd_populate_random_mac_addr(hdd_ctx, max_mac_addr - i);
313
314 if (hdd_ctx->num_provisioned_addr)
315 qdf_mem_copy(custom_mac_addr.bytes,
316 &hdd_ctx->provisioned_mac_addr[0].bytes[0],
317 sizeof(custom_mac_addr));
318 else
319 qdf_mem_copy(custom_mac_addr.bytes,
320 &hdd_ctx->derived_mac_addr[0].bytes[0],
321 sizeof(custom_mac_addr));
322
323 qdf_status = sme_set_custom_mac_addr(custom_mac_addr.bytes);
324
325 config_exit:
326 qdf_mem_free(temp);
327 release_firmware(fw);
328 return qdf_status;
329 }
330 #else
hdd_update_mac_config(struct hdd_context * hdd_ctx)331 QDF_STATUS hdd_update_mac_config(struct hdd_context *hdd_ctx)
332 {
333 return QDF_STATUS_E_NOSUPPORT;
334 }
335 #endif
336
337 /**
338 * hdd_set_power_save_offload_config() - set power save offload configuration
339 * @hdd_ctx: the pointer to hdd context
340 *
341 * Return: none
342 */
hdd_set_power_save_offload_config(struct hdd_context * hdd_ctx)343 static void hdd_set_power_save_offload_config(struct hdd_context *hdd_ctx)
344 {
345 uint32_t listen_interval = 0;
346 char *power_usage = NULL;
347
348 power_usage = ucfg_mlme_get_power_usage(hdd_ctx->psoc);
349 if (!power_usage) {
350 hdd_err("invalid power usage");
351 return;
352 }
353
354 if (strcmp(power_usage, "Min") == 0)
355 ucfg_mlme_get_bmps_min_listen_interval(hdd_ctx->psoc,
356 &listen_interval);
357 else if (strcmp(power_usage, "Max") == 0)
358 ucfg_mlme_get_bmps_max_listen_interval(hdd_ctx->psoc,
359 &listen_interval);
360 /*
361 * Based on Mode Set the LI
362 * Otherwise default LI value of 1 will
363 * be taken
364 */
365 if (listen_interval) {
366 /*
367 * setcfg for listenInterval.
368 * Make sure CFG is updated because PE reads this
369 * from CFG at the time of assoc or reassoc
370 */
371 ucfg_mlme_set_sap_listen_interval(hdd_ctx->psoc,
372 listen_interval);
373 }
374 }
375
376 #ifdef FEATURE_RUNTIME_PM
377 /**
378 * hdd_disable_runtime_pm() - Override to disable runtime_pm.
379 * @cfg_ini: Handle to struct hdd_config
380 *
381 * Return: None
382 */
hdd_disable_runtime_pm(struct hdd_config * cfg_ini)383 static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini)
384 {
385 cfg_ini->runtime_pm = 0;
386 }
387
388 /**
389 * hdd_restore_runtime_pm() - Restore runtime_pm configuration.
390 * @hdd_ctx: HDD context
391 *
392 * Return: None
393 */
hdd_restore_runtime_pm(struct hdd_context * hdd_ctx)394 static void hdd_restore_runtime_pm(struct hdd_context *hdd_ctx)
395 {
396 struct hdd_config *cfg_ini = hdd_ctx->config;
397
398 cfg_ini->runtime_pm = cfg_get(hdd_ctx->psoc, CFG_ENABLE_RUNTIME_PM);
399 }
400 #else
hdd_disable_runtime_pm(struct hdd_config * cfg_ini)401 static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini)
402 {
403 }
404
hdd_restore_runtime_pm(struct hdd_context * hdd_ctx)405 static void hdd_restore_runtime_pm(struct hdd_context *hdd_ctx)
406 {
407 }
408 #endif
409
410 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
411 /**
412 * hdd_disable_auto_shutdown() - Override to disable auto_shutdown.
413 * @cfg_ini: Handle to struct hdd_config
414 *
415 * Return: None
416 */
hdd_disable_auto_shutdown(struct hdd_config * cfg_ini)417 static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini)
418 {
419 cfg_ini->wlan_auto_shutdown = 0;
420 }
421
422 /**
423 * hdd_restore_auto_shutdown() - Restore auto_shutdown configuration.
424 * @hdd_ctx: HDD context
425 *
426 * Return: None
427 */
hdd_restore_auto_shutdown(struct hdd_context * hdd_ctx)428 static void hdd_restore_auto_shutdown(struct hdd_context *hdd_ctx)
429 {
430 struct hdd_config *cfg_ini = hdd_ctx->config;
431
432 cfg_ini->wlan_auto_shutdown = cfg_get(hdd_ctx->psoc,
433 CFG_WLAN_AUTO_SHUTDOWN);
434 }
435 #else
hdd_disable_auto_shutdown(struct hdd_config * cfg_ini)436 static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini)
437 {
438 }
439
hdd_restore_auto_shutdown(struct hdd_context * hdd_ctx)440 static void hdd_restore_auto_shutdown(struct hdd_context *hdd_ctx)
441 {
442 }
443 #endif
444
hdd_restore_all_ps(struct hdd_context * hdd_ctx)445 void hdd_restore_all_ps(struct hdd_context *hdd_ctx)
446 {
447 /*
448 * imps/bmps configuration will be restored in driver mode change
449 * sequence as part of hdd_wlan_start_modules
450 */
451
452 hdd_restore_runtime_pm(hdd_ctx);
453 hdd_restore_auto_shutdown(hdd_ctx);
454 }
455
hdd_override_all_ps(struct hdd_context * hdd_ctx)456 void hdd_override_all_ps(struct hdd_context *hdd_ctx)
457 {
458 struct hdd_config *cfg_ini = hdd_ctx->config;
459
460 ucfg_mlme_override_bmps_imps(hdd_ctx->psoc);
461 hdd_disable_runtime_pm(cfg_ini);
462 hdd_disable_auto_shutdown(cfg_ini);
463 }
464
465 /**
466 * hdd_cfg_xlate_to_csr_phy_mode() - convert PHY mode
467 * @dot11Mode: the mode to convert
468 *
469 * Convert the configuration PHY mode to CSR PHY mode
470 *
471 * Return: the CSR phy mode value
472 */
hdd_cfg_xlate_to_csr_phy_mode(enum hdd_dot11_mode dot11Mode)473 eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(enum hdd_dot11_mode dot11Mode)
474 {
475 if (cds_is_sub_20_mhz_enabled())
476 return eCSR_DOT11_MODE_abg;
477
478 switch (dot11Mode) {
479 case (eHDD_DOT11_MODE_abg):
480 return eCSR_DOT11_MODE_abg;
481 case (eHDD_DOT11_MODE_11b):
482 return eCSR_DOT11_MODE_11b;
483 case (eHDD_DOT11_MODE_11g):
484 return eCSR_DOT11_MODE_11g;
485 default:
486 case (eHDD_DOT11_MODE_11n):
487 return eCSR_DOT11_MODE_11n;
488 case (eHDD_DOT11_MODE_11g_ONLY):
489 return eCSR_DOT11_MODE_11g_ONLY;
490 case (eHDD_DOT11_MODE_11n_ONLY):
491 return eCSR_DOT11_MODE_11n_ONLY;
492 case (eHDD_DOT11_MODE_11b_ONLY):
493 return eCSR_DOT11_MODE_11b_ONLY;
494 case (eHDD_DOT11_MODE_11ac_ONLY):
495 return eCSR_DOT11_MODE_11ac_ONLY;
496 case (eHDD_DOT11_MODE_11ac):
497 return eCSR_DOT11_MODE_11ac;
498 case (eHDD_DOT11_MODE_AUTO):
499 return eCSR_DOT11_MODE_AUTO;
500 case (eHDD_DOT11_MODE_11a):
501 return eCSR_DOT11_MODE_11a;
502 case (eHDD_DOT11_MODE_11ax_ONLY):
503 return eCSR_DOT11_MODE_11ax_ONLY;
504 case (eHDD_DOT11_MODE_11ax):
505 return eCSR_DOT11_MODE_11ax;
506 #ifdef WLAN_FEATURE_11BE
507 case (eHDD_DOT11_MODE_11be):
508 return eCSR_DOT11_MODE_11be;
509 case (eHDD_DOT11_MODE_11be_ONLY):
510 return eCSR_DOT11_MODE_11be_ONLY;
511 #endif
512 }
513
514 }
515
516 /**
517 * hdd_set_idle_ps_config() - set idle power save configuration
518 * @hdd_ctx: the pointer to hdd context
519 * @val: the value to configure
520 *
521 * Return: QDF_STATUS_SUCCESS if command set correctly,
522 * otherwise the QDF_STATUS return from SME layer
523 */
hdd_set_idle_ps_config(struct hdd_context * hdd_ctx,bool val)524 QDF_STATUS hdd_set_idle_ps_config(struct hdd_context *hdd_ctx, bool val)
525 {
526 QDF_STATUS status;
527
528 hdd_debug("Enter Val %d", val);
529
530 if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) {
531 hdd_debug("Skipping powersave in FTM");
532 return QDF_STATUS_SUCCESS;
533 }
534
535 if (hdd_ctx->imps_enabled == val) {
536 hdd_nofl_debug("Already in the requested power state:%d", val);
537 return QDF_STATUS_SUCCESS;
538 }
539
540 status = sme_set_idle_powersave_config(val);
541 if (QDF_STATUS_SUCCESS != status) {
542 hdd_err("Fail to Set Idle PS Config val %d", val);
543 return status;
544 }
545
546 hdd_ctx->imps_enabled = val;
547
548 return status;
549 }
550
551 /**
552 * hdd_set_fine_time_meas_cap() - set fine timing measurement capability
553 * @hdd_ctx: HDD context
554 *
555 * This function is used to pass fine timing measurement capability coming
556 * from INI to SME. This function make sure that configure INI is supported
557 * by the device. Use bit mask to mask out the unsupported capabilities.
558 *
559 * Return: None
560 */
hdd_set_fine_time_meas_cap(struct hdd_context * hdd_ctx)561 static void hdd_set_fine_time_meas_cap(struct hdd_context *hdd_ctx)
562 {
563 uint32_t capability = 0;
564
565 ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc, &capability);
566 ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc, capability);
567 hdd_debug("fine time meas capability - Enabled: %04x", capability);
568 }
569
570 /**
571 * hdd_set_oem_6g_supported() - set oem 6g support enabled/disable
572 * @hdd_ctx: HDD context
573 *
574 * This function is used to pass oem 6g support enabled/disable value
575 * coming from INI to SME. This function make sure that configure
576 * INI is supported by the device.
577 *
578 * Return: None
579 */
hdd_set_oem_6g_supported(struct hdd_context * hdd_ctx)580 static void hdd_set_oem_6g_supported(struct hdd_context *hdd_ctx)
581 {
582 bool oem_6g_disable = true;
583 bool is_reg_6g_support, set_wifi_pos_6g_disabled;
584
585 ucfg_mlme_get_oem_6g_supported(hdd_ctx->psoc, &oem_6g_disable);
586 is_reg_6g_support = wlan_reg_is_6ghz_supported(hdd_ctx->psoc);
587 set_wifi_pos_6g_disabled = (oem_6g_disable || !is_reg_6g_support);
588
589 /**
590 * Host uses following truth table to set wifi pos 6Ghz disable in
591 * ucfg_wifi_pos_set_oem_6g_supported().
592 * -----------------------------------------------------------------
593 * oem_6g_disable INI value | reg domain 6G support | Disable 6Ghz |
594 * -----------------------------------------------------------------
595 * 1 | 1 | 1 |
596 * 1 | 0 | 1 |
597 * 0 | 1 | 0 |
598 * 0 | 0 | 1 |
599 * -----------------------------------------------------------------
600 */
601 ucfg_wifi_pos_set_oem_6g_supported(hdd_ctx->psoc,
602 set_wifi_pos_6g_disabled);
603 hdd_debug("oem 6g support is - %s",
604 set_wifi_pos_6g_disabled ? "Disabled" : "Enabled");
605 }
606
607 /**
608 * hdd_convert_string_to_array() - used to convert string into u8 array
609 * @str: String to be converted
610 * @array: Array where converted value is stored
611 * @len: Length of the populated array
612 * @array_max_len: Maximum length of the array
613 * @to_hex: true, if conversion required for hex string
614 *
615 * This API is called to convert string (each byte separated by
616 * a comma) into an u8 array
617 *
618 * Return: QDF_STATUS
619 */
620
hdd_convert_string_to_array(char * str,uint8_t * array,uint8_t * len,uint16_t array_max_len,bool to_hex)621 static QDF_STATUS hdd_convert_string_to_array(char *str, uint8_t *array,
622 uint8_t *len, uint16_t array_max_len, bool to_hex)
623 {
624 char *format, *s = str;
625
626 if (!str || !array || !len)
627 return QDF_STATUS_E_INVAL;
628
629 format = (to_hex) ? "%02x" : "%d";
630
631 *len = 0;
632 while ((s) && (*len < array_max_len)) {
633 int val;
634 /* Increment length only if sscanf successfully extracted
635 * one element. Any other return value means error.
636 * Ignore it.
637 */
638 if (sscanf(s, format, &val) == 1) {
639 array[*len] = (uint8_t) val;
640 *len += 1;
641 }
642
643 s = strpbrk(s, ",");
644 if (s)
645 s++;
646 }
647
648 return QDF_STATUS_SUCCESS;
649 }
650
hdd_string_to_u8_array(char * str,uint8_t * array,uint8_t * len,uint16_t array_max_len)651 QDF_STATUS hdd_string_to_u8_array(char *str, uint8_t *array,
652 uint8_t *len, uint16_t array_max_len)
653 {
654 return hdd_convert_string_to_array(str, array, len,
655 array_max_len, false);
656 }
657
658 /**
659 * hdd_hex_string_to_u16_array() - convert a hex string to a uint16 array
660 * @str: input string
661 * @int_array: pointer to input array of type uint16
662 * @len: pointer to number of elements which the function adds to the array
663 * @int_array_max_len: maximum number of elements in input uint16 array
664 *
665 * This function is used to convert a space separated hex string to an array of
666 * uint16_t. For example, an input string str = "a b c d" would be converted to
667 * a unint16 array, int_array = {0xa, 0xb, 0xc, 0xd}, *len = 4.
668 * This assumes that input value int_array_max_len >= 4.
669 *
670 * Return: QDF_STATUS_SUCCESS - if the conversion is successful
671 * non zero value - if the conversion is a failure
672 */
hdd_hex_string_to_u16_array(char * str,uint16_t * int_array,uint8_t * len,uint8_t int_array_max_len)673 QDF_STATUS hdd_hex_string_to_u16_array(char *str,
674 uint16_t *int_array, uint8_t *len, uint8_t int_array_max_len)
675 {
676 char *s = str;
677 uint32_t val = 0;
678
679 if (!str || !int_array || !len)
680 return QDF_STATUS_E_INVAL;
681
682 hdd_debug("str %pK intArray %pK intArrayMaxLen %d",
683 s, int_array, int_array_max_len);
684
685 *len = 0;
686
687 while ((s) && (*len < int_array_max_len)) {
688 /*
689 * Increment length only if sscanf successfully extracted one
690 * element. Any other return value means error. Ignore it.
691 */
692 if (sscanf(s, "%x", &val) == 1) {
693 int_array[*len] = (uint16_t) val;
694 hdd_debug("s %pK val %x intArray[%d]=0x%x",
695 s, val, *len, int_array[*len]);
696 *len += 1;
697 }
698 s = strpbrk(s, " ");
699 if (s)
700 s++;
701 }
702 return QDF_STATUS_SUCCESS;
703 }
704
705 /**
706 * hdd_update_config_cfg() - API to update INI setting based on hw/fw caps
707 * @hdd_ctx: pointer to hdd_ctx
708 *
709 * This API reads the cfg file which is updated with hardware/firmware
710 * capabilities and intersect it with INI setting provided by user. After
711 * taking intersection it adjust cfg it self. For example, if user has enabled
712 * RX LDPC through INI but hardware/firmware doesn't support it then disable
713 * it in CFG file here.
714 *
715 * Return: true or false based on outcome.
716 */
hdd_update_config_cfg(struct hdd_context * hdd_ctx)717 bool hdd_update_config_cfg(struct hdd_context *hdd_ctx)
718 {
719 bool status = true;
720
721 /*
722 * During the initialization both 2G and 5G capabilities should be same.
723 * So read 5G HT capability and update 2G and 5G capabilities.
724 */
725
726 if (0 != hdd_update_he_cap_in_cfg(hdd_ctx)) {
727 status = false;
728 hdd_err("Couldn't set HE CAP in cfg");
729 }
730
731 return status;
732 }
733
734 /**
735 * hdd_set_policy_mgr_user_cfg() -initializes the policy manager
736 * configuration parameters
737 *
738 * @hdd_ctx: the pointer to hdd context
739 *
740 * Return: QDF_STATUS_SUCCESS if configuration is correctly applied,
741 * otherwise the appropriate QDF_STATUS would be returned
742 */
hdd_set_policy_mgr_user_cfg(struct hdd_context * hdd_ctx)743 QDF_STATUS hdd_set_policy_mgr_user_cfg(struct hdd_context *hdd_ctx)
744 {
745 QDF_STATUS status;
746 struct policy_mgr_user_cfg *user_cfg;
747
748 user_cfg = qdf_mem_malloc(sizeof(*user_cfg));
749 if (!user_cfg)
750 return QDF_STATUS_E_NOMEM;
751
752 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc,
753 &user_cfg->enable2x2);
754 if (!QDF_IS_STATUS_SUCCESS(status))
755 hdd_err("unable to get vht_enable2x2");
756
757 user_cfg->sub_20_mhz_enabled = cds_is_sub_20_mhz_enabled();
758 status = policy_mgr_set_user_cfg(hdd_ctx->psoc, user_cfg);
759 qdf_mem_free(user_cfg);
760
761 return status;
762 }
763
hdd_to_csr_wmm_mode(uint8_t mode)764 enum wmm_user_mode hdd_to_csr_wmm_mode(uint8_t mode)
765 {
766 switch (mode) {
767 case HDD_WMM_USER_MODE_QBSS_ONLY:
768 return WMM_USER_MODE_QBSS_ONLY;
769 case HDD_WMM_USER_MODE_NO_QOS:
770 return WMM_USER_MODE_NO_QOS;
771 case HDD_WMM_USER_MODE_AUTO:
772 default:
773 return WMM_USER_MODE_AUTO;
774 }
775 }
776
777 static QDF_STATUS
hdd_set_sme_cfgs_related_to_plcy_mgr(struct hdd_context * hdd_ctx,struct sme_config_params * sme_cfg)778 hdd_set_sme_cfgs_related_to_plcy_mgr(struct hdd_context *hdd_ctx,
779 struct sme_config_params *sme_cfg)
780 {
781 uint8_t mcc_to_scc_switch = 0, is_force_1x1 = 0, allow_diff_bi = 0;
782 uint8_t conc_rule1 = 0, conc_rule2 = 0, sta_cxn_5g = 0;
783
784 if (QDF_STATUS_SUCCESS !=
785 ucfg_policy_mgr_get_mcc_scc_switch(hdd_ctx->psoc,
786 &mcc_to_scc_switch)) {
787 hdd_err("can't get mcc to scc switch");
788 return QDF_STATUS_E_FAILURE;
789 }
790 sme_cfg->csr_config.cc_switch_mode = mcc_to_scc_switch;
791
792 if (QDF_STATUS_SUCCESS !=
793 ucfg_policy_mgr_get_conc_rule1(hdd_ctx->psoc,
794 &conc_rule1)) {
795 hdd_err("can't get conc rule1");
796 return QDF_STATUS_E_FAILURE;
797 }
798 sme_cfg->csr_config.conc_custom_rule1 = conc_rule1;
799
800 if (QDF_STATUS_SUCCESS !=
801 ucfg_policy_mgr_get_conc_rule2(hdd_ctx->psoc,
802 &conc_rule2)) {
803 hdd_err("can't get conc rule2");
804 return QDF_STATUS_E_FAILURE;
805 }
806 sme_cfg->csr_config.conc_custom_rule2 = conc_rule2;
807
808 if (QDF_STATUS_SUCCESS !=
809 ucfg_policy_mgr_get_sta_cxn_5g_band(hdd_ctx->psoc,
810 &sta_cxn_5g)) {
811 hdd_err("can't get conc rule2");
812 return QDF_STATUS_E_FAILURE;
813 }
814 sme_cfg->csr_config.is_sta_connection_in_5gz_enabled = sta_cxn_5g;
815
816 if (QDF_STATUS_SUCCESS !=
817 ucfg_policy_mgr_get_force_1x1(hdd_ctx->psoc,
818 &is_force_1x1)) {
819 hdd_err("can't get force 1x1 flag");
820 return QDF_STATUS_E_FAILURE;
821 }
822 sme_cfg->csr_config.is_force_1x1 = is_force_1x1;
823
824 if (QDF_STATUS_SUCCESS !=
825 ucfg_policy_mgr_get_allow_mcc_go_diff_bi(hdd_ctx->psoc,
826 &allow_diff_bi)) {
827 hdd_err("can't get allow mcc go diff BI flag");
828 return QDF_STATUS_E_FAILURE;
829 }
830 sme_cfg->csr_config.fAllowMCCGODiffBI = allow_diff_bi;
831
832 return QDF_STATUS_SUCCESS;
833 }
834
835 #ifdef FEATURE_AP_MCC_CH_AVOIDANCE
hdd_set_sap_mcc_chnl_avoid(struct sme_config_params * sme_cfg,uint8_t val)836 static QDF_STATUS hdd_set_sap_mcc_chnl_avoid(struct sme_config_params *sme_cfg,
837 uint8_t val)
838 {
839 sme_cfg->csr_config.sap_channel_avoidance = val;
840 return QDF_STATUS_SUCCESS;
841 }
842 #else
hdd_set_sap_mcc_chnl_avoid(struct sme_config_params * sme_cfg,uint8_t val)843 static QDF_STATUS hdd_set_sap_mcc_chnl_avoid(struct sme_config_params *sme_cfg,
844 uint8_t val)
845 {
846 return QDF_STATUS_SUCCESS;
847 }
848 #endif
849
850 static
hdd_set_sme_cfgs_related_to_mlme(struct hdd_context * hdd_ctx,struct sme_config_params * sme_cfg)851 QDF_STATUS hdd_set_sme_cfgs_related_to_mlme(struct hdd_context *hdd_ctx,
852 struct sme_config_params *sme_cfg)
853 {
854 QDF_STATUS status;
855 uint8_t wmm_mode = 0, enable_mcc = 0, sap_mcc_avoid = 0;
856 uint8_t mcc_rts_cts = 0, mcc_bcast_prob_rsp = 0;
857 uint32_t mcast_mcc_rest_time = 0;
858 bool b80211e_enabled = 0;
859
860 status = ucfg_mlme_get_80211e_is_enabled(hdd_ctx->psoc,
861 &b80211e_enabled);
862 if (!QDF_IS_STATUS_SUCCESS(status)) {
863 hdd_err("Get b80211e_enabled failed");
864 return QDF_STATUS_E_FAILURE;
865 }
866 sme_cfg->csr_config.Is11eSupportEnabled = b80211e_enabled;
867
868 status = ucfg_mlme_get_wmm_mode(hdd_ctx->psoc, &wmm_mode);
869 if (!QDF_IS_STATUS_SUCCESS(status)) {
870 hdd_err("Get wmm_mode failed");
871 return QDF_STATUS_E_FAILURE;
872 }
873 sme_cfg->csr_config.WMMSupportMode = hdd_to_csr_wmm_mode(wmm_mode);
874 hdd_debug("wmm_mode=%d 802_11e_enabled=%d", wmm_mode, b80211e_enabled);
875
876 status = ucfg_mlme_get_mcc_feature(hdd_ctx->psoc, &enable_mcc);
877 if (!QDF_IS_STATUS_SUCCESS(status)) {
878 hdd_err("ucfg_mlme_get_mcc_feature fail, use def");
879 return QDF_STATUS_E_FAILURE;
880 }
881 sme_cfg->csr_config.fEnableMCCMode = enable_mcc;
882
883 status = ucfg_mlme_get_mcc_rts_cts_prot(hdd_ctx->psoc, &mcc_rts_cts);
884 if (!QDF_IS_STATUS_SUCCESS(status)) {
885 hdd_err("ucfg_mlme_get_mcc_rts_cts_prot fail, use def");
886 return QDF_STATUS_E_FAILURE;
887 }
888 sme_cfg->csr_config.mcc_rts_cts_prot_enable = mcc_rts_cts;
889
890 status = ucfg_mlme_get_mcc_bcast_prob_resp(hdd_ctx->psoc,
891 &mcc_bcast_prob_rsp);
892 if (!QDF_IS_STATUS_SUCCESS(status)) {
893 hdd_err("ucfg_mlme_get_mcc_bcast_prob_resp fail, use def");
894 return QDF_STATUS_E_FAILURE;
895 }
896 sme_cfg->csr_config.mcc_bcast_prob_resp_enable = mcc_bcast_prob_rsp;
897
898 status = ucfg_mlme_get_sta_miracast_mcc_rest_time(hdd_ctx->psoc,
899 &mcast_mcc_rest_time);
900 if (!QDF_IS_STATUS_SUCCESS(status)) {
901 hdd_err("ucfg_mlme_get_sta_miracast_mcc_rest_time, use def");
902 return QDF_STATUS_E_FAILURE;
903 }
904 sme_cfg->csr_config.f_sta_miracast_mcc_rest_time_val =
905 mcast_mcc_rest_time;
906 status = ucfg_mlme_get_sap_mcc_chnl_avoid(hdd_ctx->psoc,
907 &sap_mcc_avoid);
908 if (!QDF_IS_STATUS_SUCCESS(status)) {
909 hdd_err("ucfg_mlme_get_sap_mcc_chnl_avoid, use def");
910 return QDF_STATUS_E_FAILURE;
911 }
912 status = hdd_set_sap_mcc_chnl_avoid(sme_cfg, sap_mcc_avoid);
913
914 return status;
915 }
916
917 /**
918 * hdd_set_sme_config() -initializes the sme configuration parameters
919 *
920 * @hdd_ctx: the pointer to hdd context
921 *
922 * Return: QDF_STATUS_SUCCESS if configuration is correctly applied,
923 * otherwise the appropriate QDF_STATUS would be returned
924 */
hdd_set_sme_config(struct hdd_context * hdd_ctx)925 QDF_STATUS hdd_set_sme_config(struct hdd_context *hdd_ctx)
926 {
927 QDF_STATUS status = QDF_STATUS_SUCCESS;
928 struct sme_config_params *sme_config;
929 mac_handle_t mac_handle = hdd_ctx->mac_handle;
930 bool roam_scan_enabled;
931 bool enable_dfs_scan = true;
932 bool disconnect_nud;
933 uint32_t channel_bonding_mode;
934
935 #ifdef FEATURE_WLAN_ESE
936 bool ese_enabled;
937 #endif
938 struct hdd_config *config = hdd_ctx->config;
939 struct wlan_mlme_psoc_ext_obj *mlme_obj;
940
941 mlme_obj = mlme_get_psoc_ext_obj(hdd_ctx->psoc);
942 if (!mlme_obj)
943 return QDF_STATUS_E_INVAL;
944
945 sme_config = qdf_mem_malloc(sizeof(*sme_config));
946 if (!sme_config)
947 return QDF_STATUS_E_NOMEM;
948
949 /* Config params obtained from the registry
950 * To Do: set regulatory information here
951 */
952 sme_config->csr_config.phyMode =
953 hdd_cfg_xlate_to_csr_phy_mode(config->dot11Mode);
954
955 if (config->dot11Mode == eHDD_DOT11_MODE_abg ||
956 config->dot11Mode == eHDD_DOT11_MODE_11b ||
957 config->dot11Mode == eHDD_DOT11_MODE_11g ||
958 config->dot11Mode == eHDD_DOT11_MODE_11b_ONLY ||
959 config->dot11Mode == eHDD_DOT11_MODE_11g_ONLY) {
960 sme_config->csr_config.channelBondingMode24GHz = 0;
961 sme_config->csr_config.channelBondingMode5GHz = 0;
962 } else {
963 ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc,
964 &channel_bonding_mode);
965 sme_config->csr_config.channelBondingMode24GHz =
966 channel_bonding_mode;
967 ucfg_mlme_get_channel_bonding_5ghz(hdd_ctx->psoc,
968 &channel_bonding_mode);
969 sme_config->csr_config.channelBondingMode5GHz =
970 channel_bonding_mode;
971 }
972 /* Remaining config params not obtained from registry
973 * On RF EVB beacon using channel 1.
974 */
975 /* This param cannot be configured from INI */
976 sme_config->csr_config.send_smps_action = true;
977 sme_config->csr_config.ProprietaryRatesEnabled = 0;
978 sme_config->csr_config.HeartbeatThresh50 = 40;
979 ucfg_scan_cfg_get_dfs_chan_scan_allowed(hdd_ctx->psoc,
980 &enable_dfs_scan);
981 sme_config->csr_config.fEnableDFSChnlScan = enable_dfs_scan;
982 sme_config->csr_config.Csr11dinfo.Channels.numChannels = 0;
983 hdd_set_power_save_offload_config(hdd_ctx);
984
985 #ifdef FEATURE_WLAN_ESE
986 ucfg_mlme_is_ese_enabled(hdd_ctx->psoc, &ese_enabled);
987 if (ese_enabled)
988 ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, true);
989 #endif
990
991 ucfg_mlme_is_roam_scan_offload_enabled(hdd_ctx->psoc,
992 &roam_scan_enabled);
993
994 if (!roam_scan_enabled) {
995 /* Disable roaming in concurrency if roam scan
996 * offload is disabled
997 */
998 ucfg_mlme_set_fast_roam_in_concurrency_enabled(
999 hdd_ctx->psoc, false);
1000 }
1001
1002 /* Update maximum interfaces information */
1003 sme_config->csr_config.max_intf_count = hdd_ctx->max_intf_count;
1004
1005 hdd_set_fine_time_meas_cap(hdd_ctx);
1006 hdd_set_oem_6g_supported(hdd_ctx);
1007
1008 cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs);
1009
1010 mlme_obj->cfg.lfr.rso_user_config.policy_params.dfs_mode =
1011 STA_ROAM_POLICY_DFS_ENABLED;
1012 mlme_obj->cfg.lfr.rso_user_config.policy_params.skip_unsafe_channels = 0;
1013
1014 disconnect_nud = ucfg_dp_is_disconect_after_roam_fail(hdd_ctx->psoc);
1015 mlme_obj->cfg.lfr.disconnect_on_nud_roam_invoke_fail = disconnect_nud;
1016
1017 status = hdd_set_sme_cfgs_related_to_mlme(hdd_ctx, sme_config);
1018 if (!QDF_IS_STATUS_SUCCESS(status))
1019 hdd_err("hdd_set_sme_cfgs_related_to_mlme() fail: %d", status);
1020 status = hdd_set_sme_cfgs_related_to_plcy_mgr(hdd_ctx, sme_config);
1021 if (!QDF_IS_STATUS_SUCCESS(status))
1022 hdd_err("hdd_set_sme_cfgs_related_to_plcy_mgr fail: %d",
1023 status);
1024 hdd_debug("dot11Mode=%d", config->dot11Mode);
1025 status = sme_update_config(mac_handle, sme_config);
1026 if (!QDF_IS_STATUS_SUCCESS(status))
1027 hdd_err("sme_update_config() failure: %d", status);
1028
1029 qdf_mem_free(sme_config);
1030 return status;
1031 }
1032
1033 /**
1034 * hdd_cfg_get_global_config() - get the configuration table
1035 * @hdd_ctx: pointer to hdd context
1036 * @buf: buffer to store the configuration
1037 * @buflen: size of the buffer
1038 *
1039 * Return: none
1040 */
hdd_cfg_get_global_config(struct hdd_context * hdd_ctx,char * buf,int buflen)1041 void hdd_cfg_get_global_config(struct hdd_context *hdd_ctx, char *buf,
1042 int buflen)
1043 {
1044 ucfg_cfg_store_print(hdd_ctx->psoc);
1045
1046 snprintf(buf, buflen,
1047 "WLAN configuration written to debug log");
1048 }
1049
1050 /**
1051 * hdd_cfg_print_global_config() - print the configuration table
1052 * @hdd_ctx: pointer to hdd context
1053 *
1054 * Return: none
1055 */
hdd_cfg_print_global_config(struct hdd_context * hdd_ctx)1056 void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx)
1057 {
1058 QDF_STATUS status;
1059
1060 status = ucfg_cfg_store_print(hdd_ctx->psoc);
1061 if (QDF_IS_STATUS_ERROR(status))
1062 hdd_err("Failed to log cfg ini");
1063 }
1064
1065 /**
1066 * hdd_get_pmkid_modes() - returns PMKID mode bits
1067 * @hdd_ctx: the pointer to hdd context
1068 * @pmkid_modes: struct to update with current PMKID modes
1069 *
1070 * Return: value of pmkid_modes
1071 */
hdd_get_pmkid_modes(struct hdd_context * hdd_ctx,struct pmkid_mode_bits * pmkid_modes)1072 void hdd_get_pmkid_modes(struct hdd_context *hdd_ctx,
1073 struct pmkid_mode_bits *pmkid_modes)
1074 {
1075 uint32_t cur_pmkid_modes;
1076 QDF_STATUS status;
1077
1078 status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc, &cur_pmkid_modes);
1079 if (status != QDF_STATUS_SUCCESS)
1080 hdd_err("get pmkid modes fail");
1081
1082 pmkid_modes->fw_okc = (cur_pmkid_modes &
1083 CFG_PMKID_MODES_OKC) ? 1 : 0;
1084 pmkid_modes->fw_pmksa_cache = (cur_pmkid_modes &
1085 CFG_PMKID_MODES_PMKSA_CACHING) ? 1 : 0;
1086 }
1087
1088 static void
hdd_populate_vdev_nss(struct wlan_mlme_nss_chains * user_cfg,uint8_t tx_nss,uint8_t rx_nss,enum nss_chains_band_info band)1089 hdd_populate_vdev_nss(struct wlan_mlme_nss_chains *user_cfg,
1090 uint8_t tx_nss,
1091 uint8_t rx_nss,
1092 enum nss_chains_band_info band)
1093 {
1094 user_cfg->rx_nss[band] = rx_nss;
1095 user_cfg->tx_nss[band] = tx_nss;
1096 }
1097
hdd_set_nss_params(struct wlan_hdd_link_info * link_info,uint8_t tx_nss,uint8_t rx_nss)1098 static QDF_STATUS hdd_set_nss_params(struct wlan_hdd_link_info *link_info,
1099 uint8_t tx_nss, uint8_t rx_nss)
1100 {
1101 enum nss_chains_band_info band;
1102 struct wlan_mlme_nss_chains user_cfg;
1103 mac_handle_t mac_handle;
1104 struct hdd_adapter *adapter = link_info->adapter;
1105 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1106 struct wlan_objmgr_vdev *vdev;
1107
1108 qdf_mem_zero(&user_cfg, sizeof(user_cfg));
1109
1110 mac_handle = hdd_ctx->mac_handle;
1111 if (!mac_handle) {
1112 hdd_err("NULL MAC handle");
1113 return QDF_STATUS_E_INVAL;
1114 }
1115
1116 vdev = wlan_objmgr_get_vdev_by_id_from_pdev(hdd_ctx->pdev,
1117 link_info->vdev_id,
1118 WLAN_HDD_ID_OBJ_MGR);
1119 if (!vdev) {
1120 hdd_err("vdev is NULL %d", link_info->vdev_id);
1121 return QDF_STATUS_E_INVAL;
1122 }
1123
1124 /* For STA tx/rx nss value is updated at the time of connection,
1125 * for SAP case nss values will not get update, so can skip check
1126 * for SAP/P2P_GO mode.
1127 */
1128 if (adapter->device_mode != QDF_SAP_MODE &&
1129 adapter->device_mode != QDF_P2P_GO_MODE &&
1130 (tx_nss > wlan_vdev_mlme_get_nss(vdev) ||
1131 rx_nss > wlan_vdev_mlme_get_nss(vdev))) {
1132 hdd_err("Given tx nss/rx nss is greater than intersected nss = %d",
1133 wlan_vdev_mlme_get_nss(vdev));
1134 wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
1135 return QDF_STATUS_E_FAILURE;
1136 }
1137 wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR);
1138
1139 for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++)
1140 hdd_populate_vdev_nss(&user_cfg, tx_nss, rx_nss, band);
1141 if (QDF_IS_STATUS_ERROR(
1142 sme_nss_chains_update(mac_handle, &user_cfg,
1143 link_info->vdev_id)))
1144 return QDF_STATUS_E_FAILURE;
1145
1146 return QDF_STATUS_SUCCESS;
1147 }
1148
hdd_update_nss_in_vdev(struct wlan_hdd_link_info * link_info,mac_handle_t mac_handle,uint8_t tx_nss,uint8_t rx_nss)1149 static void hdd_update_nss_in_vdev(struct wlan_hdd_link_info *link_info,
1150 mac_handle_t mac_handle, uint8_t tx_nss,
1151 uint8_t rx_nss)
1152 {
1153 uint8_t band, max_supp_nss = MAX_VDEV_NSS;
1154 struct wlan_objmgr_vdev *vdev;
1155 struct hdd_adapter *adapter = link_info->adapter;
1156
1157 for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX;
1158 band++) {
1159 /* This API will change the global ini in mlme cfg */
1160 sme_update_nss_in_mlme_cfg(mac_handle, rx_nss, tx_nss,
1161 adapter->device_mode, band);
1162 /*
1163 * This API will change the vdev nss params in mac
1164 * context
1165 */
1166 sme_update_vdev_type_nss(mac_handle, max_supp_nss, band);
1167 }
1168 /*
1169 * This API will change the ini and dynamic nss params in
1170 * mlme vdev priv obj.
1171 */
1172 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1173 if (!vdev)
1174 return;
1175
1176 hdd_store_nss_chains_cfg_in_vdev(adapter->hdd_ctx, vdev);
1177 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1178 }
1179
hdd_set_sap_nss_params(struct wlan_hdd_link_info * link_info,mac_handle_t mac_handle,uint8_t tx_nss,uint8_t rx_nss)1180 static void hdd_set_sap_nss_params(struct wlan_hdd_link_info *link_info,
1181 mac_handle_t mac_handle,
1182 uint8_t tx_nss, uint8_t rx_nss)
1183 {
1184 hdd_update_nss_in_vdev(link_info, mac_handle, tx_nss, rx_nss);
1185 hdd_restart_sap(link_info);
1186 }
1187
1188 /**
1189 * hdd_get_sap_rx_nss() - get the sap rx nss
1190 * @link_info: Pointer to link_info
1191 * @rx_nss: pointer to rx_nss
1192 *
1193 * get the sap tx nss
1194 *
1195 * Return: None
1196 */
1197 static QDF_STATUS
hdd_get_sap_rx_nss(struct wlan_hdd_link_info * link_info,uint8_t * rx_nss)1198 hdd_get_sap_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
1199 {
1200 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1201 struct wlan_objmgr_vdev *vdev;
1202 struct wlan_mlme_nss_chains *dynamic_cfg;
1203 enum band_info operating_band;
1204 mac_handle_t mac_handle;
1205 uint8_t vdev_nss;
1206
1207 mac_handle = hdd_ctx->mac_handle;
1208 if (!mac_handle) {
1209 hdd_debug("NULL MAC handle");
1210 return QDF_STATUS_E_INVAL;
1211 }
1212
1213 operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
1214 if (operating_band == BAND_UNKNOWN)
1215 return QDF_STATUS_E_INVAL;
1216
1217 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1218 if (!vdev)
1219 return QDF_STATUS_E_INVAL;
1220
1221 sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band);
1222 if (hdd_ctx->dynamic_nss_chains_support) {
1223 dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
1224 if (!dynamic_cfg) {
1225 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1226 hdd_debug("nss chain dynamic config NULL");
1227 return QDF_STATUS_E_INVAL;
1228 }
1229 switch (operating_band) {
1230 case BAND_2G:
1231 *rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ];
1232 break;
1233 case BAND_5G:
1234 *rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ];
1235 break;
1236 default:
1237 hdd_debug("Band %d Not 2G or 5G", operating_band);
1238 break;
1239 }
1240 } else {
1241 *rx_nss = vdev_nss;
1242 }
1243
1244 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1245 return QDF_STATUS_SUCCESS;
1246 }
1247
1248 /**
1249 * hdd_get_sap_tx_nss() - get the sap tx nss
1250 * @link_info: Pointer of link_info
1251 * @tx_nss: pointer to tx_nss
1252 *
1253 * get the sap tx nss
1254 *
1255 * Return: None
1256 */
1257 static QDF_STATUS
hdd_get_sap_tx_nss(struct wlan_hdd_link_info * link_info,uint8_t * tx_nss)1258 hdd_get_sap_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
1259 {
1260 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1261 struct wlan_objmgr_vdev *vdev;
1262 struct wlan_mlme_nss_chains *dynamic_cfg;
1263 enum band_info operating_band;
1264 mac_handle_t mac_handle;
1265 uint8_t vdev_nss;
1266
1267 mac_handle = hdd_ctx->mac_handle;
1268 if (!mac_handle) {
1269 hdd_debug("NULL MAC handle");
1270 return QDF_STATUS_E_INVAL;
1271 }
1272
1273 operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
1274 if (operating_band == BAND_UNKNOWN)
1275 return QDF_STATUS_E_INVAL;
1276
1277 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1278 if (!vdev)
1279 return QDF_STATUS_E_INVAL;
1280
1281 sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band);
1282 if (hdd_ctx->dynamic_nss_chains_support) {
1283 dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
1284 if (!dynamic_cfg) {
1285 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1286 hdd_debug("nss chain dynamic config NULL");
1287 return QDF_STATUS_E_INVAL;
1288 }
1289 switch (operating_band) {
1290 case BAND_2G:
1291 *tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ];
1292 break;
1293 case BAND_5G:
1294 *tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ];
1295 break;
1296 default:
1297 hdd_debug("Band %d Not 2G or 5G", operating_band);
1298 break;
1299 }
1300 } else {
1301 *tx_nss = vdev_nss;
1302 }
1303
1304 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1305 return QDF_STATUS_SUCCESS;
1306 }
1307
1308 static bool
hdd_get_sap_restart_required_for_nss(struct wlan_hdd_link_info * link_info,uint8_t tx_nss,uint8_t rx_nss)1309 hdd_get_sap_restart_required_for_nss(struct wlan_hdd_link_info *link_info,
1310 uint8_t tx_nss, uint8_t rx_nss)
1311 {
1312 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1313 uint8_t rx_prev, tx_prev;
1314 bool restart_sap = 0;
1315
1316 ucfg_mlme_get_restart_sap_on_dynamic_nss_chains_cfg(hdd_ctx->psoc,
1317 &restart_sap);
1318
1319 if (!restart_sap)
1320 return false;
1321
1322 hdd_get_sap_rx_nss(link_info, &rx_prev);
1323 hdd_get_sap_tx_nss(link_info, &tx_prev);
1324
1325 if (rx_prev != rx_nss && tx_prev != tx_nss)
1326 return true;
1327 return false;
1328 }
1329
hdd_update_nss(struct wlan_hdd_link_info * link_info,uint8_t tx_nss,uint8_t rx_nss)1330 QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info,
1331 uint8_t tx_nss, uint8_t rx_nss)
1332 {
1333 struct hdd_adapter *adapter = link_info->adapter;
1334 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1335 uint32_t rx_supp_data_rate, tx_supp_data_rate;
1336 bool status = true;
1337 QDF_STATUS qdf_status;
1338 qdf_size_t val_len;
1339 struct mlme_ht_capabilities_info ht_cap_info;
1340 uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET] = {0};
1341 uint8_t mcs_set_temp[SIZE_OF_SUPPORTED_MCS_SET];
1342 uint8_t enable2x2;
1343 mac_handle_t mac_handle;
1344 bool bval = 0, restart_sap = 0;
1345
1346 if ((tx_nss == 2 || rx_nss == 2) && (hdd_ctx->num_rf_chains != 2)) {
1347 hdd_err("No support for 2 spatial streams");
1348 return QDF_STATUS_E_INVAL;
1349 }
1350
1351 if (tx_nss > MAX_VDEV_NSS || rx_nss > MAX_VDEV_NSS) {
1352 hdd_debug("Cannot support tx_nss: %d rx_nss: %d", tx_nss,
1353 rx_nss);
1354 return QDF_STATUS_E_INVAL;
1355 }
1356
1357 qdf_status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
1358 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1359 hdd_err("unable to get vht_enable2x2");
1360 return QDF_STATUS_E_FAILURE;
1361 }
1362
1363 mac_handle = hdd_ctx->mac_handle;
1364 if (!mac_handle) {
1365 hdd_err("NULL MAC handle");
1366 return QDF_STATUS_E_INVAL;
1367 }
1368
1369 /*
1370 * If FW is supporting the dynamic nss update, this command is meant to
1371 * be per vdev, so update only the ini params of that particular vdev
1372 * and not the global param enable2x2
1373 */
1374 if (hdd_ctx->dynamic_nss_chains_support) {
1375 restart_sap =
1376 hdd_get_sap_restart_required_for_nss(link_info, tx_nss, rx_nss);
1377
1378 if ((adapter->device_mode == QDF_SAP_MODE ||
1379 adapter->device_mode == QDF_P2P_GO_MODE) && restart_sap) {
1380 if ((tx_nss == 2 && rx_nss == 2) ||
1381 (tx_nss == 1 && rx_nss == 1)) {
1382 hdd_set_sap_nss_params(link_info, mac_handle,
1383 tx_nss, rx_nss);
1384 return QDF_STATUS_SUCCESS;
1385 }
1386 hdd_err("tx_nss %d rx_nss %d not supported ",
1387 tx_nss, rx_nss);
1388 return QDF_STATUS_E_FAILURE;
1389 }
1390
1391 if (hdd_is_vdev_in_conn_state(link_info))
1392 return hdd_set_nss_params(link_info, tx_nss, rx_nss);
1393
1394 if (tx_nss != rx_nss) {
1395 hdd_err("TX NSS = %d, RX NSS = %d value mismatch, doesn't support asymmetric config in disconnected state",
1396 tx_nss, rx_nss);
1397 return QDF_STATUS_E_FAILURE;
1398 }
1399 hdd_debug("Vdev %d in disconnect state, changing ini nss params",
1400 link_info->vdev_id);
1401 if (!bval) {
1402 hdd_err("Nss in 1x1, no change required, 2x2 mode disabled");
1403 return QDF_STATUS_SUCCESS;
1404 }
1405
1406 hdd_update_nss_in_vdev(link_info, mac_handle, tx_nss, rx_nss);
1407 sme_set_nss_capability(mac_handle, link_info->vdev_id,
1408 rx_nss, adapter->device_mode);
1409
1410 return QDF_STATUS_SUCCESS;
1411 }
1412
1413 /*
1414 * The code below is executed only when fw doesn't support dynamic
1415 * update of nss and chains per vdev feature, for the upcoming
1416 * connection
1417 */
1418 enable2x2 = (rx_nss == 2) ? 1 : 0;
1419
1420 if (bval == enable2x2) {
1421 hdd_debug("NSS same as requested");
1422 return QDF_STATUS_SUCCESS;
1423 }
1424
1425 if (sme_is_any_session_in_connected_state(mac_handle)) {
1426 hdd_err("Connected sessions present, Do not change NSS");
1427 return QDF_STATUS_E_INVAL;
1428 }
1429
1430 qdf_status = ucfg_mlme_set_vht_enable2x2(hdd_ctx->psoc, enable2x2);
1431 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1432 hdd_err("Failed to set vht_enable2x2");
1433 return QDF_STATUS_E_FAILURE;
1434 }
1435
1436 if (tx_nss == 1 && rx_nss == 2) {
1437 /* 1x2 */
1438 rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2;
1439 tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1;
1440 } else if (enable2x2) {
1441 /* 2x2 */
1442 rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2;
1443 tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2;
1444 } else {
1445 /* 1x1 */
1446 rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1;
1447 tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1;
1448 }
1449
1450 /* Update Rx Highest Long GI data Rate */
1451 qdf_status =
1452 ucfg_mlme_cfg_set_vht_rx_supp_data_rate(hdd_ctx->psoc,
1453 rx_supp_data_rate);
1454 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1455 hdd_err("Failed to set rx_supp_data_rate");
1456 status = false;
1457 }
1458 /* Update Tx Highest Long GI data Rate */
1459 qdf_status =
1460 ucfg_mlme_cfg_set_vht_tx_supp_data_rate(hdd_ctx->psoc,
1461 tx_supp_data_rate);
1462 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1463 hdd_err("Failed to set tx_supp_data_rate");
1464 status = false;
1465 }
1466
1467 qdf_status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, &ht_cap_info);
1468 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1469 hdd_err("Failed to get HT Cap info");
1470 goto skip_ht_cap_update;
1471 }
1472
1473 if (!(hdd_ctx->ht_tx_stbc_supported && enable2x2)) {
1474 ht_cap_info.tx_stbc = 0;
1475 } else {
1476 qdf_status =
1477 ucfg_mlme_cfg_get_vht_tx_stbc(hdd_ctx->psoc, &bval);
1478 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1479 hdd_err("Failed to get vht_tx_stbc");
1480 ht_cap_info.tx_stbc = bval;
1481 }
1482 }
1483
1484 qdf_status = ucfg_mlme_set_ht_cap_info(hdd_ctx->psoc, ht_cap_info);
1485 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1486 hdd_err("Could not set the HT_CAP_INFO");
1487 }
1488 skip_ht_cap_update:
1489 qdf_status = ucfg_mlme_update_nss_vht_cap(hdd_ctx->psoc);
1490 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
1491 hdd_err("Failed to set update_nss_vht_cap");
1492 status = false;
1493 }
1494
1495 #define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff
1496 val_len = SIZE_OF_SUPPORTED_MCS_SET;
1497 qdf_status = ucfg_mlme_get_supported_mcs_set(hdd_ctx->psoc,
1498 mcs_set_temp,
1499 &val_len);
1500 if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
1501 mcs_set[0] = mcs_set_temp[0];
1502 if (enable2x2)
1503 for (val_len = 0; val_len < rx_nss; val_len++)
1504 mcs_set[val_len] =
1505 WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES;
1506 if (ucfg_mlme_set_supported_mcs_set(
1507 hdd_ctx->psoc, mcs_set,
1508 (qdf_size_t)SIZE_OF_SUPPORTED_MCS_SET) ==
1509 QDF_STATUS_E_FAILURE) {
1510 status = false;
1511 hdd_err("Could not pass on MCS SET to CFG");
1512 }
1513 } else {
1514 status = false;
1515 hdd_err("Could not get MCS SET from CFG");
1516 }
1517 sme_set_nss_capability(mac_handle, link_info->vdev_id,
1518 rx_nss, adapter->device_mode);
1519 #undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES
1520
1521 if (QDF_STATUS_SUCCESS != sme_update_nss(mac_handle, rx_nss))
1522 status = false;
1523
1524 hdd_set_policy_mgr_user_cfg(hdd_ctx);
1525
1526 return (status == false) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS;
1527 }
1528
hdd_get_nss(struct hdd_adapter * adapter,uint8_t * nss)1529 QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss)
1530 {
1531 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1532 bool bval;
1533 QDF_STATUS status = QDF_STATUS_SUCCESS;
1534
1535 /*
1536 * If FW is supporting the dynamic nss update, this command is meant to
1537 * be per vdev, so get nss in the ini params of that particular vdev
1538 * otherwise get it from the global param enable2x2
1539 */
1540 if (hdd_ctx->dynamic_nss_chains_support) {
1541 uint8_t nss_2g, nss_5g;
1542
1543 sme_get_vdev_type_nss(adapter->device_mode, &nss_2g, &nss_5g);
1544 /* Different settings in 2G and 5G is not supported */
1545 *nss = nss_2g;
1546 } else {
1547 status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval);
1548 if (!QDF_IS_STATUS_SUCCESS(status)) {
1549 hdd_err("unable to get vht_enable2x2");
1550 return status;
1551 }
1552
1553 *nss = (bval) ? 2 : 1;
1554 if (!policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc) &&
1555 policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc))
1556 *nss = *nss - 1;
1557 }
1558
1559 return status;
1560 }
1561
1562 /**
1563 * hdd_get_sap_num_tx_chains() - get the sap num tx chains
1564 * @link_info: Pointer of link_info
1565 * @tx_chains: pointer to tx_chains
1566 *
1567 * get the sap num tx chains
1568 *
1569 * Return: None
1570 */
1571 static QDF_STATUS
hdd_get_sap_num_tx_chains(struct wlan_hdd_link_info * link_info,uint8_t * tx_chains)1572 hdd_get_sap_num_tx_chains(struct wlan_hdd_link_info *link_info,
1573 uint8_t *tx_chains)
1574 {
1575 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1576 struct wlan_objmgr_vdev *vdev;
1577 struct wlan_mlme_nss_chains *dynamic_cfg;
1578 enum band_info operating_band;
1579 mac_handle_t mac_handle;
1580
1581 mac_handle = hdd_ctx->mac_handle;
1582 if (!mac_handle) {
1583 hdd_debug("NULL MAC handle");
1584 return QDF_STATUS_E_INVAL;
1585 }
1586
1587 operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
1588 if (operating_band == BAND_UNKNOWN)
1589 return QDF_STATUS_E_INVAL;
1590
1591 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1592 if (!vdev)
1593 return QDF_STATUS_E_INVAL;
1594
1595 if (hdd_ctx->dynamic_nss_chains_support) {
1596 dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
1597 if (!dynamic_cfg) {
1598 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1599 hdd_debug("nss chain dynamic config NULL");
1600 return QDF_STATUS_E_INVAL;
1601 }
1602 switch (operating_band) {
1603 case BAND_2G:
1604 *tx_chains =
1605 dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ];
1606 break;
1607 case BAND_5G:
1608 *tx_chains =
1609 dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ];
1610 break;
1611 default:
1612 hdd_debug("Band %d Not 2G or 5G", operating_band);
1613 break;
1614 }
1615 }
1616
1617 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1618 return QDF_STATUS_SUCCESS;
1619 }
1620
1621 /**
1622 * hdd_get_sta_num_tx_chains() - get the sta num tx chains
1623 * @link_info: Pointer of link_info
1624 * @tx_chains: pointer to tx_chains
1625 *
1626 * get the STA num tx chains
1627 *
1628 * Return: None
1629 */
1630 static QDF_STATUS
hdd_get_sta_num_tx_chains(struct wlan_hdd_link_info * link_info,uint8_t * tx_chains)1631 hdd_get_sta_num_tx_chains(struct wlan_hdd_link_info *link_info,
1632 uint8_t *tx_chains)
1633 {
1634 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1635 struct wlan_objmgr_vdev *vdev;
1636 QDF_STATUS status;
1637
1638 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1639 if (!vdev)
1640 return QDF_STATUS_E_INVAL;
1641
1642 status = ucfg_mlme_get_sta_num_tx_chains(hdd_ctx->psoc, vdev,
1643 tx_chains);
1644 if (QDF_IS_STATUS_ERROR(status))
1645 hdd_err("Failed to get sta_tx_nss");
1646
1647 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1648
1649 return status;
1650 }
1651
1652 /**
1653 * hdd_get_sta_tx_nss() - get the sta tx nss
1654 * @link_info: Pointer of link_info
1655 * @tx_nss: pointer to tx_nss
1656 *
1657 * get the STA tx nss
1658 *
1659 * Return: None
1660 */
1661 static QDF_STATUS
hdd_get_sta_tx_nss(struct wlan_hdd_link_info * link_info,uint8_t * tx_nss)1662 hdd_get_sta_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
1663 {
1664 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1665 struct wlan_objmgr_vdev *vdev;
1666 QDF_STATUS status;
1667
1668 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1669 if (!vdev)
1670 return QDF_STATUS_E_INVAL;
1671
1672 status = ucfg_mlme_get_sta_tx_nss(hdd_ctx->psoc, vdev, tx_nss);
1673 if (QDF_IS_STATUS_ERROR(status))
1674 hdd_err("Failed to get sta_tx_nss");
1675
1676 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1677
1678 return status;
1679 }
1680
hdd_get_num_tx_chains(struct wlan_hdd_link_info * link_info,uint8_t * tx_chains)1681 QDF_STATUS hdd_get_num_tx_chains(struct wlan_hdd_link_info *link_info,
1682 uint8_t *tx_chains)
1683 {
1684 struct hdd_adapter *adapter = link_info->adapter;
1685 QDF_STATUS status = QDF_STATUS_SUCCESS;
1686
1687 if (adapter->device_mode == QDF_SAP_MODE ||
1688 adapter->device_mode == QDF_P2P_GO_MODE)
1689 status = hdd_get_sap_num_tx_chains(link_info, tx_chains);
1690 else
1691 status = hdd_get_sta_num_tx_chains(link_info, tx_chains);
1692
1693 return status;
1694 }
1695
hdd_get_tx_nss(struct wlan_hdd_link_info * link_info,uint8_t * tx_nss)1696 QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss)
1697 {
1698 struct hdd_adapter *adapter = link_info->adapter;
1699 QDF_STATUS status = QDF_STATUS_SUCCESS;
1700
1701 if (adapter->device_mode == QDF_SAP_MODE ||
1702 adapter->device_mode == QDF_P2P_GO_MODE)
1703 status = hdd_get_sap_tx_nss(link_info, tx_nss);
1704 else
1705 status = hdd_get_sta_tx_nss(link_info, tx_nss);
1706
1707 return status;
1708 }
1709
1710 /**
1711 * hdd_get_sap_num_rx_chains() - get the sap num rx chains
1712 * @link_info: Pointer to link_info
1713 * @rx_chains: pointer to rx_chains
1714 *
1715 * get the sap num rx chains
1716 *
1717 * Return: None
1718 */
1719 static QDF_STATUS
hdd_get_sap_num_rx_chains(struct wlan_hdd_link_info * link_info,uint8_t * rx_chains)1720 hdd_get_sap_num_rx_chains(struct wlan_hdd_link_info *link_info,
1721 uint8_t *rx_chains)
1722 {
1723 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1724 struct wlan_objmgr_vdev *vdev;
1725 struct wlan_mlme_nss_chains *dynamic_cfg;
1726 enum band_info operating_band;
1727 mac_handle_t mac_handle;
1728
1729 mac_handle = hdd_ctx->mac_handle;
1730 if (!mac_handle) {
1731 hdd_debug("NULL MAC handle");
1732 return QDF_STATUS_E_INVAL;
1733 }
1734
1735 operating_band = hdd_get_sap_operating_band_by_link_info(link_info);
1736 if (operating_band == BAND_UNKNOWN)
1737 return QDF_STATUS_E_INVAL;
1738
1739 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1740 if (!vdev)
1741 return QDF_STATUS_E_INVAL;
1742
1743 if (hdd_ctx->dynamic_nss_chains_support) {
1744 dynamic_cfg = mlme_get_dynamic_vdev_config(vdev);
1745 if (!dynamic_cfg) {
1746 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1747 hdd_debug("nss chain dynamic config NULL");
1748 return QDF_STATUS_E_INVAL;
1749 }
1750 switch (operating_band) {
1751 case BAND_2G:
1752 *rx_chains =
1753 dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ];
1754 break;
1755 case BAND_5G:
1756 *rx_chains =
1757 dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ];
1758 break;
1759 default:
1760 hdd_debug("Band %d Not 2G or 5G", operating_band);
1761 break;
1762 }
1763 }
1764
1765 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1766 return QDF_STATUS_SUCCESS;
1767 }
1768
1769 /**
1770 * hdd_get_sta_num_rx_chains() - get the sta num rx chains
1771 * @link_info: Pointer to link_info in adapter
1772 * @rx_chains: pointer to rx_chains
1773 *
1774 * get the STA num rx chains
1775 *
1776 * Return: QDF_STATUS_SUCCESS if the RX NSS is returned, otherwise a suitable
1777 * QDF_STATUS_E_* error code
1778 */
1779 static QDF_STATUS
hdd_get_sta_num_rx_chains(struct wlan_hdd_link_info * link_info,uint8_t * rx_chains)1780 hdd_get_sta_num_rx_chains(struct wlan_hdd_link_info *link_info,
1781 uint8_t *rx_chains)
1782 {
1783 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1784 struct wlan_objmgr_vdev *vdev;
1785 QDF_STATUS status;
1786
1787 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1788 if (!vdev)
1789 return QDF_STATUS_E_INVAL;
1790
1791 status = ucfg_mlme_get_sta_num_rx_chains(hdd_ctx->psoc, vdev,
1792 rx_chains);
1793 if (QDF_IS_STATUS_ERROR(status))
1794 hdd_err("Failed to get sta_rx_nss");
1795
1796 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1797
1798 return status;
1799 }
1800
1801 /**
1802 * hdd_get_sta_rx_nss() - get the sta rx nss
1803 * @link_info: Pointer to link_info in adapter
1804 * @rx_nss: pointer to rx_nss
1805 *
1806 * get the STA rx nss
1807 *
1808 * Return: QDF_STATUS_SUCCESS if the RX NSS is returned, otherwise a suitable
1809 * QDF_STATUS_E_* error code
1810 */
1811 static QDF_STATUS
hdd_get_sta_rx_nss(struct wlan_hdd_link_info * link_info,uint8_t * rx_nss)1812 hdd_get_sta_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
1813 {
1814 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
1815 struct wlan_objmgr_vdev *vdev;
1816 QDF_STATUS status;
1817
1818 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
1819 if (!vdev)
1820 return QDF_STATUS_E_INVAL;
1821
1822 status = wlan_mlme_get_sta_rx_nss(hdd_ctx->psoc, vdev, rx_nss);
1823 if (QDF_IS_STATUS_ERROR(status))
1824 hdd_err("Failed to get sta_rx_nss");
1825
1826 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
1827
1828 return status;
1829 }
1830
hdd_get_num_rx_chains(struct wlan_hdd_link_info * link_info,uint8_t * rx_chains)1831 QDF_STATUS hdd_get_num_rx_chains(struct wlan_hdd_link_info *link_info,
1832 uint8_t *rx_chains)
1833 {
1834 QDF_STATUS status = QDF_STATUS_SUCCESS;
1835 struct hdd_adapter *adapter = link_info->adapter;
1836
1837 if (adapter->device_mode == QDF_SAP_MODE ||
1838 adapter->device_mode == QDF_P2P_GO_MODE)
1839 status = hdd_get_sap_num_rx_chains(link_info, rx_chains);
1840 else
1841 status = hdd_get_sta_num_rx_chains(link_info, rx_chains);
1842
1843 return status;
1844 }
1845
hdd_get_rx_nss(struct wlan_hdd_link_info * link_info,uint8_t * rx_nss)1846 QDF_STATUS hdd_get_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss)
1847 {
1848 QDF_STATUS status = QDF_STATUS_SUCCESS;
1849 struct hdd_adapter *adapter = link_info->adapter;
1850
1851 if (adapter->device_mode == QDF_SAP_MODE ||
1852 adapter->device_mode == QDF_P2P_GO_MODE)
1853 status = hdd_get_sap_rx_nss(link_info, rx_nss);
1854 else
1855 status = hdd_get_sta_rx_nss(link_info, rx_nss);
1856
1857 return status;
1858 }
1859
hdd_phymode_to_vendor_mode(eCsrPhyMode csr_phy_mode,enum qca_wlan_vendor_phy_mode * vendor_phy_mode)1860 int hdd_phymode_to_vendor_mode(eCsrPhyMode csr_phy_mode,
1861 enum qca_wlan_vendor_phy_mode *vendor_phy_mode)
1862 {
1863 switch (csr_phy_mode) {
1864 case eCSR_DOT11_MODE_AUTO:
1865 case eCSR_DOT11_MODE_11be:
1866 case eCSR_DOT11_MODE_11be_ONLY:
1867 *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_AUTO;
1868 break;
1869 case eCSR_DOT11_MODE_11a:
1870 *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11A;
1871 break;
1872 case eCSR_DOT11_MODE_11b:
1873 case eCSR_DOT11_MODE_11b_ONLY:
1874 *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11B;
1875 break;
1876 case eCSR_DOT11_MODE_11g:
1877 case eCSR_DOT11_MODE_11g_ONLY:
1878 *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11G;
1879 break;
1880 case eCSR_DOT11_MODE_11n:
1881 case eCSR_DOT11_MODE_11n_ONLY:
1882 *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11AGN;
1883 break;
1884 case eCSR_DOT11_MODE_11ac:
1885 case eCSR_DOT11_MODE_11ac_ONLY:
1886 *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160;
1887 break;
1888 case eCSR_DOT11_MODE_11ax:
1889 case eCSR_DOT11_MODE_11ax_ONLY:
1890 *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160;
1891 break;
1892 case eCSR_DOT11_MODE_abg:
1893 default:
1894 hdd_err("Not supported mode %d", csr_phy_mode);
1895 return -EINVAL;
1896 }
1897
1898 return 0;
1899 }
1900
hdd_vendor_mode_to_phymode(enum qca_wlan_vendor_phy_mode vendor_phy_mode,eCsrPhyMode * csr_phy_mode)1901 int hdd_vendor_mode_to_phymode(enum qca_wlan_vendor_phy_mode vendor_phy_mode,
1902 eCsrPhyMode *csr_phy_mode)
1903 {
1904 switch (vendor_phy_mode) {
1905 case QCA_WLAN_VENDOR_PHY_MODE_AUTO:
1906 case QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO:
1907 case QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO:
1908 *csr_phy_mode = eCSR_DOT11_MODE_AUTO;
1909 break;
1910 case QCA_WLAN_VENDOR_PHY_MODE_11A:
1911 *csr_phy_mode = eCSR_DOT11_MODE_11a;
1912 break;
1913 case QCA_WLAN_VENDOR_PHY_MODE_11B:
1914 *csr_phy_mode = eCSR_DOT11_MODE_11b;
1915 break;
1916 case QCA_WLAN_VENDOR_PHY_MODE_11G:
1917 *csr_phy_mode = eCSR_DOT11_MODE_11g;
1918 break;
1919 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20:
1920 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40:
1921 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS:
1922 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS:
1923 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20:
1924 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40:
1925 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS:
1926 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS:
1927 case QCA_WLAN_VENDOR_PHY_MODE_11AGN:
1928 *csr_phy_mode = eCSR_DOT11_MODE_11n;
1929 break;
1930 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20:
1931 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40:
1932 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS:
1933 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS:
1934 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80:
1935 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80:
1936 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160:
1937 *csr_phy_mode = eCSR_DOT11_MODE_11ac;
1938 break;
1939 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20:
1940 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40:
1941 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS:
1942 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS:
1943 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80:
1944 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80:
1945 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160:
1946 *csr_phy_mode = eCSR_DOT11_MODE_11ax;
1947 break;
1948 default:
1949 hdd_err("Not supported mode %d", vendor_phy_mode);
1950 return -EINVAL;
1951 }
1952
1953 return 0;
1954 }
1955
hdd_vendor_mode_to_band(enum qca_wlan_vendor_phy_mode vendor_phy_mode,uint8_t * supported_band,bool is_6ghz_supported)1956 int hdd_vendor_mode_to_band(enum qca_wlan_vendor_phy_mode vendor_phy_mode,
1957 uint8_t *supported_band, bool is_6ghz_supported)
1958 {
1959 switch (vendor_phy_mode) {
1960 case QCA_WLAN_VENDOR_PHY_MODE_AUTO:
1961 if (is_6ghz_supported)
1962 *supported_band = REG_BAND_MASK_ALL;
1963 else
1964 *supported_band =
1965 BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
1966 break;
1967 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20:
1968 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40:
1969 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS:
1970 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS:
1971 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80:
1972 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80:
1973 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160:
1974 *supported_band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
1975 break;
1976 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20:
1977 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40:
1978 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS:
1979 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS:
1980 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80:
1981 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80:
1982 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160:
1983 case QCA_WLAN_VENDOR_PHY_MODE_11AGN:
1984 if (is_6ghz_supported)
1985 *supported_band = REG_BAND_MASK_ALL;
1986 else
1987 *supported_band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G);
1988 break;
1989 case QCA_WLAN_VENDOR_PHY_MODE_11A:
1990 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20:
1991 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40:
1992 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS:
1993 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS:
1994 case QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO:
1995 *supported_band = BIT(REG_BAND_5G);
1996 break;
1997 case QCA_WLAN_VENDOR_PHY_MODE_11B:
1998 case QCA_WLAN_VENDOR_PHY_MODE_11G:
1999 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20:
2000 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40:
2001 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS:
2002 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS:
2003 case QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO:
2004 *supported_band = BIT(REG_BAND_2G);
2005 break;
2006 default:
2007 hdd_err("Not supported mode %d", vendor_phy_mode);
2008 return -EINVAL;
2009 }
2010
2011 return 0;
2012 }
2013
2014 int
hdd_vendor_mode_to_bonding_mode(enum qca_wlan_vendor_phy_mode vendor_phy_mode,uint32_t * bonding_mode)2015 hdd_vendor_mode_to_bonding_mode(enum qca_wlan_vendor_phy_mode vendor_phy_mode,
2016 uint32_t *bonding_mode)
2017 {
2018 switch (vendor_phy_mode) {
2019 case QCA_WLAN_VENDOR_PHY_MODE_AUTO:
2020 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40:
2021 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS:
2022 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS:
2023 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40:
2024 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS:
2025 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS:
2026 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40:
2027 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS:
2028 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS:
2029 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80:
2030 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80:
2031 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160:
2032 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40:
2033 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS:
2034 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS:
2035 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80:
2036 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80:
2037 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160:
2038 case QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO:
2039 case QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO:
2040 case QCA_WLAN_VENDOR_PHY_MODE_11AGN:
2041 *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE;
2042 break;
2043 case QCA_WLAN_VENDOR_PHY_MODE_11A:
2044 case QCA_WLAN_VENDOR_PHY_MODE_11B:
2045 case QCA_WLAN_VENDOR_PHY_MODE_11G:
2046 case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20:
2047 case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20:
2048 case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20:
2049 case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20:
2050 *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
2051 break;
2052 default:
2053 hdd_err("Not supported mode %d", vendor_phy_mode);
2054 return -EINVAL;
2055 }
2056
2057 return 0;
2058 }
2059
hdd_phymode_to_dot11_mode(eCsrPhyMode phymode,enum hdd_dot11_mode * dot11_mode)2060 int hdd_phymode_to_dot11_mode(eCsrPhyMode phymode,
2061 enum hdd_dot11_mode *dot11_mode)
2062 {
2063 switch (phymode) {
2064 case eCSR_DOT11_MODE_AUTO:
2065 case eCSR_DOT11_MODE_11be:
2066 *dot11_mode = eHDD_DOT11_MODE_AUTO;
2067 break;
2068 case eCSR_DOT11_MODE_11a:
2069 *dot11_mode = eHDD_DOT11_MODE_11a;
2070 break;
2071 case eCSR_DOT11_MODE_11b:
2072 *dot11_mode = eHDD_DOT11_MODE_11b;
2073 break;
2074 case eCSR_DOT11_MODE_11g:
2075 *dot11_mode = eHDD_DOT11_MODE_11g;
2076 break;
2077 case eCSR_DOT11_MODE_11n:
2078 *dot11_mode = eHDD_DOT11_MODE_11n;
2079 break;
2080 case eCSR_DOT11_MODE_11ac:
2081 *dot11_mode = eHDD_DOT11_MODE_11ac;
2082 break;
2083 case eCSR_DOT11_MODE_11ax:
2084 *dot11_mode = eHDD_DOT11_MODE_11ax;
2085 break;
2086 default:
2087 hdd_err("Not supported mode %d", phymode);
2088 return -EINVAL;
2089 }
2090
2091 return 0;
2092 }
2093
2094 #ifdef QCA_HT_2040_COEX
2095 static QDF_STATUS
hdd_set_ht2040_mode(struct hdd_adapter * adapter,struct csr_config_params * csr_config,uint32_t bonding_mode)2096 hdd_set_ht2040_mode(struct hdd_adapter *adapter,
2097 struct csr_config_params *csr_config,
2098 uint32_t bonding_mode)
2099 {
2100 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2101 QDF_STATUS status = QDF_STATUS_SUCCESS;
2102
2103 if (csr_config->phyMode == eCSR_DOT11_MODE_11n) {
2104 if (bonding_mode == WNI_CFG_CHANNEL_BONDING_MODE_ENABLE)
2105 csr_config->obssEnabled = true;
2106 else
2107 csr_config->obssEnabled = false;
2108 status = sme_set_ht2040_mode(hdd_ctx->mac_handle,
2109 adapter->deflink->vdev_id,
2110 eHT_CHAN_HT20,
2111 csr_config->obssEnabled);
2112 }
2113
2114 return status;
2115 }
2116 #else
2117 static QDF_STATUS
hdd_set_ht2040_mode(struct hdd_adapter * adapter,struct csr_config_params * csr_config,uint32_t bonding_mode)2118 hdd_set_ht2040_mode(struct hdd_adapter *adapter,
2119 struct csr_config_params *csr_config,
2120 uint32_t bonding_mode)
2121 {
2122 return QDF_STATUS_SUCCESS;
2123 }
2124 #endif
2125
hdd_update_phymode(struct hdd_adapter * adapter,eCsrPhyMode phymode,uint8_t supported_band,uint32_t bonding_mode)2126 int hdd_update_phymode(struct hdd_adapter *adapter, eCsrPhyMode phymode,
2127 uint8_t supported_band, uint32_t bonding_mode)
2128 {
2129 struct net_device *net = adapter->dev;
2130 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
2131 struct sme_config_params *sme_config = NULL;
2132 struct csr_config_params *csr_config;
2133 eCsrPhyMode old_phymode;
2134 enum hdd_dot11_mode hdd_dot11mode;
2135 int ret = 0;
2136 QDF_STATUS status;
2137
2138 ret = wlan_hdd_validate_context(hdd_ctx);
2139 if (ret < 0)
2140 return ret;
2141
2142 ret = hdd_phymode_to_dot11_mode(phymode, &hdd_dot11mode);
2143 if (ret < 0)
2144 return ret;
2145
2146 hdd_debug("phymode=%d bonding_mode=%d supported_band=%d",
2147 phymode, bonding_mode, supported_band);
2148
2149 old_phymode = sme_get_phy_mode(hdd_ctx->mac_handle);
2150
2151 sme_set_phy_mode(hdd_ctx->mac_handle, phymode);
2152
2153 if (hdd_reg_set_band(net, supported_band)) {
2154 sme_set_phy_mode(hdd_ctx->mac_handle, old_phymode);
2155 return -EIO;
2156 }
2157
2158 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2159 if (!sme_config)
2160 return -ENOMEM;
2161
2162 sme_get_config_param(hdd_ctx->mac_handle, sme_config);
2163 csr_config = &sme_config->csr_config;
2164 csr_config->phyMode = phymode;
2165
2166 status = hdd_set_ht2040_mode(adapter, csr_config, bonding_mode);
2167 if (QDF_IS_STATUS_ERROR(status)) {
2168 hdd_err("Failed to set ht2040 mode");
2169 ret = -EIO;
2170 goto free;
2171 }
2172
2173 status = ucfg_mlme_set_band_capability(hdd_ctx->psoc, supported_band);
2174 if (QDF_IS_STATUS_ERROR(status)) {
2175 hdd_err("failed to set MLME band capability");
2176 ret = -EIO;
2177 goto free;
2178 }
2179
2180 if (supported_band == BIT(REG_BAND_2G)) {
2181 status = ucfg_mlme_set_11h_enabled(hdd_ctx->psoc, 0);
2182 if (!QDF_IS_STATUS_SUCCESS(status)) {
2183 hdd_err("Failed to set 11h_enable flag");
2184 ret = -EIO;
2185 goto free;
2186 }
2187 }
2188 if (supported_band & BIT(REG_BAND_2G))
2189 csr_config->channelBondingMode24GHz = bonding_mode;
2190
2191 if (supported_band & BIT(REG_BAND_5G))
2192 csr_config->channelBondingMode5GHz = bonding_mode;
2193
2194 sme_update_config(hdd_ctx->mac_handle, sme_config);
2195
2196 hdd_ctx->config->dot11Mode = hdd_dot11mode;
2197 ucfg_mlme_set_channel_bonding_24ghz(hdd_ctx->psoc,
2198 csr_config->channelBondingMode24GHz);
2199 ucfg_mlme_set_channel_bonding_5ghz(hdd_ctx->psoc,
2200 csr_config->channelBondingMode5GHz);
2201 if (hdd_update_config_cfg(hdd_ctx) == false) {
2202 hdd_err("could not update config_dat");
2203 ret = -EIO;
2204 goto free;
2205 }
2206
2207 if (supported_band & BIT(REG_BAND_5G)) {
2208 struct ieee80211_supported_band *ieee_band;
2209 uint32_t channel_bonding_mode;
2210
2211 ucfg_mlme_get_channel_bonding_5ghz(hdd_ctx->psoc,
2212 &channel_bonding_mode);
2213 ieee_band = hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ];
2214 if (channel_bonding_mode)
2215 ieee_band->ht_cap.cap |=
2216 IEEE80211_HT_CAP_SUP_WIDTH_20_40;
2217 else
2218 ieee_band->ht_cap.cap &=
2219 ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
2220 }
2221
2222 free:
2223 if (sme_config)
2224 qdf_mem_free(sme_config);
2225 return ret;
2226 }
2227
hdd_get_ldpc(struct hdd_adapter * adapter,int * value)2228 int hdd_get_ldpc(struct hdd_adapter *adapter, int *value)
2229 {
2230 mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
2231 int ret;
2232
2233 hdd_enter();
2234 ret = sme_get_ht_config(mac_handle, adapter->deflink->vdev_id,
2235 WNI_CFG_HT_CAP_INFO_ADVANCE_CODING);
2236 if (ret < 0) {
2237 hdd_err("Failed to get LDPC value");
2238 } else {
2239 *value = ret;
2240 ret = 0;
2241 }
2242 return ret;
2243 }
2244
hdd_set_ldpc(struct wlan_hdd_link_info * link_info,int value)2245 int hdd_set_ldpc(struct wlan_hdd_link_info *link_info, int value)
2246 {
2247 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2248 mac_handle_t mac_handle = hdd_ctx->mac_handle;
2249 int ret;
2250 QDF_STATUS status;
2251 struct mlme_ht_capabilities_info ht_cap_info;
2252
2253 hdd_debug("%d", value);
2254
2255 if (!mac_handle) {
2256 hdd_err("NULL Mac handle");
2257 return -EINVAL;
2258 }
2259
2260 status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, &ht_cap_info);
2261 if (QDF_IS_STATUS_ERROR(status)) {
2262 hdd_err("Failed to get HT capability info");
2263 return -EIO;
2264 }
2265
2266 ht_cap_info.adv_coding_cap = value;
2267 status = ucfg_mlme_set_ht_cap_info(hdd_ctx->psoc, ht_cap_info);
2268 if (QDF_IS_STATUS_ERROR(status)) {
2269 hdd_err("Failed to set HT capability info");
2270 return -EIO;
2271 }
2272 status = ucfg_mlme_cfg_set_vht_ldpc_coding_cap(hdd_ctx->psoc, value);
2273 if (QDF_IS_STATUS_ERROR(status)) {
2274 hdd_err("Failed to set VHT LDPC capability info");
2275 return -EIO;
2276 }
2277 ret = sme_update_ht_config(mac_handle, link_info->vdev_id,
2278 WNI_CFG_HT_CAP_INFO_ADVANCE_CODING, value);
2279 if (ret)
2280 hdd_err("Failed to set LDPC value");
2281 ret = sme_update_he_ldpc_supp(mac_handle,
2282 link_info->vdev_id, value);
2283 if (ret)
2284 hdd_err("Failed to set HE LDPC value");
2285 ret = sme_set_auto_rate_ldpc(mac_handle, link_info->vdev_id,
2286 (value ? 0 : 1));
2287
2288 return ret;
2289 }
2290
hdd_get_tx_stbc(struct hdd_adapter * adapter,int * value)2291 int hdd_get_tx_stbc(struct hdd_adapter *adapter, int *value)
2292 {
2293 mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
2294 int ret;
2295
2296 hdd_enter();
2297 ret = sme_get_ht_config(mac_handle, adapter->deflink->vdev_id,
2298 WNI_CFG_HT_CAP_INFO_TX_STBC);
2299 if (ret < 0) {
2300 hdd_err("Failed to get TX STBC value");
2301 } else {
2302 *value = ret;
2303 ret = 0;
2304 }
2305
2306 return ret;
2307 }
2308
hdd_set_tx_stbc(struct wlan_hdd_link_info * link_info,int value)2309 int hdd_set_tx_stbc(struct wlan_hdd_link_info *link_info, int value)
2310 {
2311 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2312 mac_handle_t mac_handle = hdd_ctx->mac_handle;
2313 int ret;
2314 QDF_STATUS status;
2315 struct mlme_ht_capabilities_info ht_cap_info;
2316
2317 hdd_debug("%d", value);
2318
2319 if (!mac_handle) {
2320 hdd_err("NULL Mac handle");
2321 return -EINVAL;
2322 }
2323
2324 if (value) {
2325 /* make sure HT capabilities allow this */
2326 status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc,
2327 &ht_cap_info);
2328 if (QDF_IS_STATUS_ERROR(status)) {
2329 hdd_err("Failed to get HT capability info");
2330 return -EIO;
2331 }
2332 if (!ht_cap_info.tx_stbc) {
2333 hdd_err("TX STBC not supported");
2334 return -EINVAL;
2335 }
2336 }
2337 ret = sme_update_ht_config(mac_handle, link_info->vdev_id,
2338 WNI_CFG_HT_CAP_INFO_TX_STBC,
2339 value);
2340 if (ret)
2341 hdd_err("Failed to set TX STBC value");
2342 ret = sme_update_he_tx_stbc_cap(mac_handle,
2343 link_info->vdev_id, value);
2344 if (ret)
2345 hdd_err("Failed to set HE TX STBC value");
2346
2347 return ret;
2348 }
2349
hdd_get_rx_stbc(struct hdd_adapter * adapter,int * value)2350 int hdd_get_rx_stbc(struct hdd_adapter *adapter, int *value)
2351 {
2352 mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle;
2353 int ret;
2354
2355 hdd_enter();
2356 ret = sme_get_ht_config(mac_handle, adapter->deflink->vdev_id,
2357 WNI_CFG_HT_CAP_INFO_RX_STBC);
2358 if (ret < 0) {
2359 hdd_err("Failed to get RX STBC value");
2360 } else {
2361 *value = ret;
2362 ret = 0;
2363 }
2364
2365 return ret;
2366 }
2367
hdd_set_rx_stbc(struct wlan_hdd_link_info * link_info,int value)2368 int hdd_set_rx_stbc(struct wlan_hdd_link_info *link_info, int value)
2369 {
2370 struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2371 mac_handle_t mac_handle = hdd_ctx->mac_handle;
2372 int ret;
2373 QDF_STATUS status;
2374 struct mlme_ht_capabilities_info ht_cap_info;
2375
2376 hdd_debug("%d", value);
2377
2378 if (!mac_handle) {
2379 hdd_err("NULL Mac handle");
2380 return -EINVAL;
2381 }
2382
2383 if (value) {
2384 /* make sure HT capabilities allow this */
2385 status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc,
2386 &ht_cap_info);
2387 if (QDF_IS_STATUS_ERROR(status)) {
2388 hdd_err("Failed to get HT capability info");
2389 return -EIO;
2390 }
2391 if (!ht_cap_info.rx_stbc) {
2392 hdd_warn("RX STBC not supported");
2393 return -EINVAL;
2394 }
2395 }
2396 ret = sme_update_ht_config(mac_handle, link_info->vdev_id,
2397 WNI_CFG_HT_CAP_INFO_RX_STBC,
2398 value);
2399 if (ret)
2400 hdd_err("Failed to set RX STBC value");
2401
2402 ret = sme_update_he_rx_stbc_cap(mac_handle,
2403 link_info->vdev_id, value);
2404 if (ret)
2405 hdd_err("Failed to set HE RX STBC value");
2406
2407 return ret;
2408 }
2409
2410 /**
2411 * hdd_convert_chwidth_to_phy_chwidth() - convert channel width of type enum
2412 * eSirMacHTChannelWidth to enum phy_ch_width
2413 * @chwidth: channel width of type enum eSirMacHTChannelWidth
2414 *
2415 * Return: channel width of type enum phy_ch_width
2416 */
2417 static enum phy_ch_width
hdd_convert_chwidth_to_phy_chwidth(enum eSirMacHTChannelWidth chwidth)2418 hdd_convert_chwidth_to_phy_chwidth(enum eSirMacHTChannelWidth chwidth)
2419 {
2420 enum phy_ch_width ch_width = CH_WIDTH_INVALID;
2421
2422 switch (chwidth) {
2423 case eHT_CHANNEL_WIDTH_20MHZ:
2424 ch_width = CH_WIDTH_20MHZ;
2425 break;
2426 case eHT_CHANNEL_WIDTH_40MHZ:
2427 ch_width = CH_WIDTH_40MHZ;
2428 break;
2429 case eHT_CHANNEL_WIDTH_80MHZ:
2430 ch_width = CH_WIDTH_80MHZ;
2431 break;
2432 case eHT_CHANNEL_WIDTH_160MHZ:
2433 ch_width = CH_WIDTH_160MHZ;
2434 break;
2435 case eHT_CHANNEL_WIDTH_80P80MHZ:
2436 ch_width = CH_WIDTH_80P80MHZ;
2437 break;
2438 case eHT_CHANNEL_WIDTH_320MHZ:
2439 ch_width = CH_WIDTH_320MHZ;
2440 break;
2441 default:
2442 hdd_debug("Invalid channel width %d", chwidth);
2443 break;
2444 }
2445
2446 return ch_width;
2447 }
2448
2449 /**
2450 * hdd_update_bss_rate_flags() - update bss rate flag as per new channel width
2451 * @link_info: Link info in HDD adapter
2452 * @psoc: psoc common object
2453 * @cw: channel width for which bss rate flag being updated
2454 *
2455 * Return: QDF_STATUS
2456 */
2457 static QDF_STATUS
hdd_update_bss_rate_flags(struct wlan_hdd_link_info * link_info,struct wlan_objmgr_psoc * psoc,enum phy_ch_width cw)2458 hdd_update_bss_rate_flags(struct wlan_hdd_link_info *link_info,
2459 struct wlan_objmgr_psoc *psoc, enum phy_ch_width cw)
2460 {
2461 struct hdd_station_ctx *hdd_sta_ctx;
2462 uint8_t eht_present, he_present, vht_present, ht_present;
2463
2464 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
2465
2466 eht_present = hdd_sta_ctx->conn_info.conn_flag.eht_present;
2467 he_present = hdd_sta_ctx->conn_info.conn_flag.he_present;
2468 vht_present = hdd_sta_ctx->conn_info.conn_flag.vht_present;
2469 ht_present = hdd_sta_ctx->conn_info.conn_flag.ht_present;
2470
2471 return ucfg_mlme_update_bss_rate_flags(psoc, link_info->vdev_id,
2472 cw, eht_present, he_present,
2473 vht_present, ht_present);
2474 }
2475
2476 /**
2477 * struct sme_config_msg_ctx - sme config update message ctx
2478 * @vdev: vdev object
2479 * @chwidth: channel width
2480 * @is_restore: restore default or not
2481 * @bonding_mode: bonding mode
2482 */
2483 struct sme_config_msg_ctx {
2484 struct wlan_objmgr_vdev *vdev;
2485 enum eSirMacHTChannelWidth chwidth;
2486 bool is_restore;
2487 uint32_t bonding_mode;
2488 };
2489
2490 /**
2491 * hdd_restore_sme_config_cb() - restore bonding mode sme config cb
2492 * @msg: msg data
2493 *
2494 * Return: QDF_STATUS
2495 */
hdd_restore_sme_config_cb(struct scheduler_msg * msg)2496 static QDF_STATUS hdd_restore_sme_config_cb(struct scheduler_msg *msg)
2497 {
2498 struct hdd_context *hdd_ctx;
2499 mac_handle_t mac_handle;
2500 struct sme_config_params *sme_config = NULL;
2501 struct sme_config_msg_ctx *sme_config_msg_ctx = NULL;
2502 struct wlan_objmgr_vdev *vdev = NULL;
2503 uint8_t vdev_id;
2504 QDF_STATUS status = QDF_STATUS_E_FAILURE;
2505
2506 if (!msg) {
2507 hdd_debug("msg is null");
2508 return QDF_STATUS_E_INVAL;
2509 }
2510
2511 sme_config_msg_ctx = msg->bodyptr;
2512 if (!sme_config_msg_ctx) {
2513 hdd_debug("bodyptr is null");
2514 return QDF_STATUS_E_INVAL;
2515 }
2516
2517 vdev = sme_config_msg_ctx->vdev;
2518 if (!vdev)
2519 goto end;
2520
2521 hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
2522 if (wlan_hdd_validate_context(hdd_ctx))
2523 goto end;
2524
2525 mac_handle = cds_get_context(QDF_MODULE_ID_SME);
2526 if (!mac_handle)
2527 goto end;
2528
2529 if (!hdd_ctx->psoc)
2530 goto end;
2531
2532 sme_config = qdf_mem_malloc(sizeof(*sme_config));
2533 if (!sme_config)
2534 goto end;
2535
2536 vdev_id = wlan_vdev_get_id(vdev);
2537 hdd_debug("vdev id %d is_restore %d bonding_mode %d chwdith %d",
2538 vdev_id,
2539 sme_config_msg_ctx->is_restore,
2540 sme_config_msg_ctx->bonding_mode,
2541 sme_config_msg_ctx->chwidth);
2542 sme_get_config_param(mac_handle, sme_config);
2543 if (sme_config_msg_ctx->is_restore) {
2544 sme_config->csr_config.channelBondingMode5GHz =
2545 cfg_get(hdd_ctx->psoc, CFG_CHANNEL_BONDING_MODE_5GHZ);
2546 sme_config->csr_config.channelBondingMode24GHz =
2547 cfg_get(hdd_ctx->psoc, CFG_CHANNEL_BONDING_MODE_24GHZ);
2548 } else {
2549 sme_config->csr_config.channelBondingMode5GHz =
2550 sme_config_msg_ctx->bonding_mode;
2551 sme_config->csr_config.channelBondingMode24GHz =
2552 sme_config_msg_ctx->bonding_mode;
2553 }
2554 sme_update_config(mac_handle, sme_config);
2555 sme_set_he_bw_cap(hdd_ctx->mac_handle, vdev_id,
2556 sme_config_msg_ctx->chwidth);
2557 sme_set_eht_bw_cap(hdd_ctx->mac_handle, vdev_id,
2558 sme_config_msg_ctx->chwidth);
2559
2560 status = QDF_STATUS_SUCCESS;
2561 end:
2562 qdf_mem_free(sme_config);
2563 if (vdev)
2564 hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
2565 qdf_mem_free(sme_config_msg_ctx);
2566
2567 return status;
2568 }
2569
2570 /**
2571 * hdd_restore_sme_config_flush_cb() - bonding mode sme config flush cb
2572 * @msg: msg data
2573 *
2574 * Return: QDF_STATUS
2575 */
hdd_restore_sme_config_flush_cb(struct scheduler_msg * msg)2576 static QDF_STATUS hdd_restore_sme_config_flush_cb(struct scheduler_msg *msg)
2577 {
2578 struct sme_config_msg_ctx *sme_config_msg_ctx;
2579
2580 if (!msg) {
2581 hdd_debug("msg is null");
2582 return QDF_STATUS_E_INVAL;
2583 }
2584
2585 sme_config_msg_ctx = msg->bodyptr;
2586 if (!sme_config_msg_ctx) {
2587 hdd_debug("bodyptr is null");
2588 return QDF_STATUS_E_INVAL;
2589 }
2590
2591 if (sme_config_msg_ctx->vdev)
2592 hdd_objmgr_put_vdev_by_user(sme_config_msg_ctx->vdev,
2593 WLAN_HDD_ID_OBJ_MGR);
2594 else
2595 hdd_debug("vdev is null");
2596
2597 qdf_mem_free(sme_config_msg_ctx);
2598
2599 return QDF_STATUS_SUCCESS;
2600 }
2601
2602 /**
2603 * hdd_restore_sme_config() - restore bonding mode for sme config
2604 * @link_info: link info
2605 * @chwidth: channel width
2606 * @is_restore: msg data
2607 * @bonding_mode: bonding mode
2608 *
2609 * Return: void
2610 */
hdd_restore_sme_config(struct wlan_hdd_link_info * link_info,enum eSirMacHTChannelWidth chwidth,bool is_restore,uint32_t bonding_mode)2611 static void hdd_restore_sme_config(struct wlan_hdd_link_info *link_info,
2612 enum eSirMacHTChannelWidth chwidth,
2613 bool is_restore, uint32_t bonding_mode)
2614 {
2615 struct scheduler_msg msg = {0};
2616 QDF_STATUS status;
2617 struct wlan_objmgr_vdev *vdev;
2618 struct sme_config_msg_ctx *sme_config_msg_ctx;
2619
2620 sme_config_msg_ctx = qdf_mem_malloc(sizeof(*sme_config_msg_ctx));
2621 if (!sme_config_msg_ctx)
2622 return;
2623
2624 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR);
2625 if (!vdev) {
2626 qdf_mem_free(sme_config_msg_ctx);
2627 hdd_debug("no vdev from link info");
2628 return;
2629 }
2630
2631 sme_config_msg_ctx->vdev = vdev;
2632 sme_config_msg_ctx->chwidth = chwidth;
2633 sme_config_msg_ctx->is_restore = is_restore;
2634 sme_config_msg_ctx->bonding_mode = bonding_mode;
2635 msg.bodyptr = sme_config_msg_ctx;
2636 msg.callback = hdd_restore_sme_config_cb;
2637 msg.flush_callback = hdd_restore_sme_config_flush_cb;
2638
2639 status = scheduler_post_message(QDF_MODULE_ID_HDD,
2640 QDF_MODULE_ID_OS_IF,
2641 QDF_MODULE_ID_OS_IF, &msg);
2642 if (QDF_IS_STATUS_ERROR(status)) {
2643 hdd_debug("status %d", status);
2644 hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
2645 qdf_mem_free(sme_config_msg_ctx);
2646 }
2647 }
2648
2649 /**
2650 * wlan_update_mlo_link_chn_width() - API to update mlo link chn width
2651 * @adapter: the pointer to adapter
2652 * @ch_width: channel width to update
2653 * @link_id: mlo link id
2654 *
2655 * Get link id and channel bandwidth from user space and save in link_info.
2656 * When link switch happen and host driver connect done, if the link change
2657 * from standby to non-standby, ch_width will send to fw again.
2658 *
2659 * Return: QDF_STATUS
2660 */
2661
2662 #if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV)
2663 static struct wlan_hdd_link_info *
wlan_update_mlo_link_chn_width(struct hdd_adapter * adapter,enum phy_ch_width ch_width,uint8_t link_id)2664 wlan_update_mlo_link_chn_width(struct hdd_adapter *adapter,
2665 enum phy_ch_width ch_width,
2666 uint8_t link_id)
2667 {
2668 struct wlan_hdd_link_info *link_info;
2669 struct hdd_station_ctx *sta_ctx;
2670
2671 link_info = hdd_get_link_info_by_ieee_link_id(adapter, link_id);
2672 if (!link_info)
2673 return NULL;
2674
2675 sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info);
2676
2677 sta_ctx->user_cfg_chn_width = ch_width;
2678 hdd_debug("save ch_width:%u to link_id:%u vdev_id:%u",
2679 ch_width, link_id, link_info->vdev_id);
2680
2681 return link_info;
2682 }
2683 #else
2684 static struct wlan_hdd_link_info *
wlan_update_mlo_link_chn_width(struct hdd_adapter * adapter,enum phy_ch_width ch_width,uint8_t link_id)2685 wlan_update_mlo_link_chn_width(struct hdd_adapter *adapter,
2686 enum phy_ch_width ch_width,
2687 uint8_t link_id)
2688 {
2689 return NULL;
2690 }
2691 #endif
2692
hdd_update_channel_width(struct wlan_hdd_link_info * link_info,enum eSirMacHTChannelWidth chwidth,uint32_t bonding_mode,uint8_t link_id,bool is_restore)2693 int hdd_update_channel_width(struct wlan_hdd_link_info *link_info,
2694 enum eSirMacHTChannelWidth chwidth,
2695 uint32_t bonding_mode, uint8_t link_id,
2696 bool is_restore)
2697 {
2698 struct hdd_context *hdd_ctx;
2699 int ret;
2700 enum phy_ch_width ch_width;
2701 struct wlan_objmgr_vdev *link_vdev;
2702 struct wlan_objmgr_vdev *vdev;
2703 struct wlan_hdd_link_info *link_info_t;
2704 uint8_t link_vdev_id;
2705 enum QDF_OPMODE op_mode;
2706 QDF_STATUS status;
2707 uint8_t vdev_id = link_info->vdev_id;
2708 enum phy_ch_width new_ch_width;
2709
2710 hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter);
2711 if (!hdd_ctx) {
2712 hdd_err("hdd_ctx failure");
2713 return -EINVAL;
2714 }
2715
2716 op_mode = link_info->adapter->device_mode;
2717 if (op_mode != QDF_STA_MODE) {
2718 hdd_debug("vdev %d: op mode %d, CW update not supported",
2719 vdev_id, op_mode);
2720 return -EINVAL;
2721 }
2722
2723 vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID);
2724 if (!vdev) {
2725 hdd_err("vdev %d: vdev not found", vdev_id);
2726 return -EINVAL;
2727 }
2728
2729 ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth);
2730
2731 /**
2732 * Link_id check is for disconnect restore process.
2733 * Disconnect will not update channel bandwidth into cache struct.
2734 */
2735 if (wlan_vdev_mlme_is_mlo_vdev(vdev) &&
2736 link_id != WLAN_INVALID_LINK_ID) {
2737 link_info_t = wlan_update_mlo_link_chn_width(link_info->adapter,
2738 ch_width, link_id);
2739 if (!link_info_t) {
2740 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
2741 return -EINVAL;
2742 }
2743
2744 hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID);
2745
2746 link_vdev = hdd_objmgr_get_vdev_by_user(link_info_t,
2747 WLAN_OSIF_ID);
2748 if (!link_vdev)
2749 return 0;
2750
2751 link_vdev_id = link_info_t->vdev_id;
2752 status = wlan_mlme_get_bw_no_punct(hdd_ctx->psoc,
2753 link_vdev,
2754 wlan_vdev_mlme_get_des_chan(link_vdev),
2755 &new_ch_width);
2756 if (QDF_IS_STATUS_SUCCESS(status) && ch_width > new_ch_width)
2757 ch_width = new_ch_width;
2758 } else {
2759 link_vdev = vdev;
2760 link_vdev_id = vdev_id;
2761 link_info_t = link_info;
2762 }
2763
2764 if (ucfg_mlme_is_chwidth_with_notify_supported(hdd_ctx->psoc) &&
2765 hdd_cm_is_vdev_connected(link_info_t)) {
2766 ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth);
2767 hdd_debug("vdev %d : process update ch width request to %d",
2768 link_vdev_id, ch_width);
2769 status = ucfg_mlme_send_ch_width_update_with_notify(hdd_ctx->psoc,
2770 link_vdev,
2771 ch_width,
2772 link_vdev_id);
2773
2774 if (QDF_IS_STATUS_ERROR(status)) {
2775 hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
2776 return -EIO;
2777 }
2778 status = hdd_update_bss_rate_flags(link_info_t, hdd_ctx->psoc,
2779 ch_width);
2780 if (QDF_IS_STATUS_ERROR(status)) {
2781 hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
2782 return -EIO;
2783 }
2784
2785 hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
2786 return 0;
2787 }
2788 hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID);
2789
2790 ret = wma_cli_set_command(link_vdev_id, wmi_vdev_param_chwidth,
2791 chwidth, VDEV_CMD);
2792 if (ret)
2793 return ret;
2794
2795 hdd_restore_sme_config(link_info_t, chwidth, is_restore, bonding_mode);
2796
2797 return 0;
2798 }
2799