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