qcacld-3.0: [11AX] Add support to configure 11ax rate

Add support for to configure 11ax rates using set_11ax_rate
iwpriv command.

Change-Id: I55ab5cc3b51f92ab5c2e347d3b17e392456b90b8
CRs-Fixed: 1073481
diff --git a/core/hdd/inc/qc_sap_ioctl.h b/core/hdd/inc/qc_sap_ioctl.h
index a7a7865..b5971e1 100644
--- a/core/hdd/inc/qc_sap_ioctl.h
+++ b/core/hdd/inc/qc_sap_ioctl.h
@@ -191,6 +191,9 @@
 #define RC_2_RATE_IDX_11AC(_rc)         ((_rc) & 0xf)
 #define HT_RC_2_STREAMS_11AC(_rc)       ((((_rc) & 0x30) >> 4) + 1)
 
+#define RC_2_RATE_IDX_11AX(_rc)         ((_rc) & 0x1f)
+#define HT_RC_2_STREAMS_11AX(_rc)       (((_rc) >> 5) & 0x7)
+
 enum {
 	QCSAP_PARAM_MAX_ASSOC = 1,
 	QCSAP_PARAM_GET_WLAN_DBG,
@@ -252,6 +255,7 @@
 	QCASAP_PARAM_RX_STBC,
 	QCSAP_PARAM_CHAN_WIDTH,
 	QCSAP_PARAM_SET_TXRX_STATS,
+	QCASAP_SET_11AX_RATE,
 };
 
 int iw_get_channel_list(struct net_device *dev,
diff --git a/core/hdd/inc/wlan_hdd_wext.h b/core/hdd/inc/wlan_hdd_wext.h
index b949041..1d62e7a 100644
--- a/core/hdd/inc/wlan_hdd_wext.h
+++ b/core/hdd/inc/wlan_hdd_wext.h
@@ -36,6 +36,8 @@
 #include <linux/timer.h>
 #include "qdf_event.h"
 
+struct sap_Config;
+
 /*
  * order of parameters in addTs private ioctl
  */
@@ -384,6 +386,31 @@
 int hdd_get_rx_stbc(hdd_adapter_t *adapter, int *value);
 int hdd_set_rx_stbc(hdd_adapter_t *adapter, int value);
 
+/**
+ * hdd_assemble_rate_code() - assemble rate code to be sent to FW
+ * @preamble: rate preamble
+ * @nss: number of streams
+ * @rate: rate index
+ *
+ * Rate code assembling is different for targets which are 11ax capable.
+ * Check for the target support and assemble the rate code accordingly.
+ *
+ * Return: assembled rate code
+ */
+int hdd_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate);
+
+/**
+ * hdd_set_11ax_rate() - set 11ax rate
+ * @adapter: adapter being modified
+ * @value: new 11ax rate code
+ * @sap_config: pointer to SAP config to check HW mode
+ *              this will be NULL for call from STA persona
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+int hdd_set_11ax_rate(hdd_adapter_t *adapter, int value,
+		      struct sap_Config *sap_config);
+
 void wlan_hdd_change_country_code_callback(void *pAdapter);
 
 int hdd_set_band(struct net_device *dev, u8 ui_band);
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 4e02570..6188e96 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -2990,7 +2990,7 @@
 				}
 				preamble = WMI_RATE_PREAMBLE_OFDM;
 			}
-			set_value = (preamble << 6) | (nss << 4) | rix;
+			set_value = hdd_assemble_rate_code(preamble, nss, rix);
 		}
 		hdd_notice("SET_HT_RATE val %d rix %d preamble %x nss %d",
 		       set_value, rix, preamble, nss);
@@ -3015,11 +3015,11 @@
 		}
 
 		if (set_value != 0xff) {
-		rix = RC_2_RATE_IDX_11AC(set_value);
-		preamble = WMI_RATE_PREAMBLE_VHT;
-		nss = HT_RC_2_STREAMS_11AC(set_value) - 1;
+			rix = RC_2_RATE_IDX_11AC(set_value);
+			preamble = WMI_RATE_PREAMBLE_VHT;
+			nss = HT_RC_2_STREAMS_11AC(set_value) - 1;
 
-			set_value = (preamble << 6) | (nss << 4) | rix;
+			set_value = hdd_assemble_rate_code(preamble, nss, rix);
 		}
 		hdd_notice("SET_VHT_RATE val %d rix %d preamble %x nss %d",
 		       set_value, rix, preamble, nss);
@@ -3033,7 +3033,6 @@
 	case QCASAP_SHORT_GI:
 	{
 		hdd_notice("QCASAP_SET_SHORT_GI val %d", set_value);
-
 		/* same as 40MHZ */
 		ret = sme_update_ht_config(hHal, pHostapdAdapter->sessionId,
 					   WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ,
@@ -3302,7 +3301,11 @@
 	case QCASAP_PARAM_RX_STBC:
 		ret = hdd_set_rx_stbc(pHostapdAdapter, set_value);
 		break;
-
+	case QCASAP_SET_11AX_RATE:
+		ret = hdd_set_11ax_rate(pHostapdAdapter, set_value,
+					&pHostapdAdapter->sessionCtx.ap.
+					sapConfig);
+		break;
 	default:
 		hdd_err("Invalid setparam command %d value %d",
 		       sub_cmd, set_value);
@@ -3452,8 +3455,7 @@
 	case QCASAP_SHORT_GI:
 	{
 		*value = (int)sme_get_ht_config(hHal,
-						pHostapdAdapter->
-						sessionId,
+						pHostapdAdapter->sessionId,
 						WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ);
 		break;
 	}
@@ -5764,7 +5766,12 @@
 	}
 	,
 #endif
-
+	{
+		QCASAP_SET_11AX_RATE,
+		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+		0, "set_11ax_rate"
+	}
+	,
 };
 
 static const iw_handler hostapd_private[] = {
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index c5ef4cf..2d8bc33 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -1011,6 +1011,26 @@
 #define WE_SET_CONC_SYSTEM_PREF               89
 #define WE_SET_TXRX_STATS                     90
 
+/*
+ * <ioctl>
+ * set_11ax_rate - set 11ax rates to FW
+ *
+ * @INPUT: rate code
+ *
+ * @OUTPUT: None
+ *
+ * This IOCTL fixes the Tx data rate of 11AX.
+ *
+ * @E.g: iwpriv wlan0 set_11ax_rate <rate code>
+ *
+ * Supported Feature: STA/SAP
+ *
+ * Usage: Internal
+ *
+ * </ioctl>
+ */
+#define WE_SET_11AX_RATE                      91
+
 /* Private ioctls and their sub-ioctls */
 #define WLAN_PRIV_SET_NONE_GET_INT    (SIOCIWFIRSTPRIV + 1)
 #define WE_GET_11D_STATE     1
@@ -3952,6 +3972,54 @@
 	return ret;
 }
 
+int hdd_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate)
+{
+	int set_value;
+
+	if (sme_is_feature_supported_by_fw(DOT11AX))
+		set_value = WMI_ASSEMBLE_RATECODE_V1(rate, nss, preamble);
+	else
+		set_value = (preamble << 6) | (nss << 4) | rate;
+
+	return set_value;
+}
+
+int hdd_set_11ax_rate(hdd_adapter_t *adapter, int set_value,
+		      struct sap_Config *sap_config)
+{
+	uint8_t preamble = 0, nss = 0, rix = 0;
+	int ret;
+
+	if (!sap_config) {
+		if (!sme_is_feature_supported_by_fw(DOT11AX)) {
+			hdd_err("Target does not support 11ax");
+			return -EIO;
+		}
+	} else if (sap_config->SapHw_mode != eCSR_DOT11_MODE_11ax &&
+		   sap_config->SapHw_mode != eCSR_DOT11_MODE_11ax_ONLY) {
+			hdd_err("Invalid hw mode, SAP hw_mode= 0x%x, ch = %d",
+				sap_config->SapHw_mode, sap_config->channel);
+			return -EIO;
+	}
+
+	if (set_value != 0xff) {
+		rix = RC_2_RATE_IDX_11AX(set_value);
+		preamble = WMI_RATE_PREAMBLE_HE;
+		nss = HT_RC_2_STREAMS_11AX(set_value);
+
+		set_value = hdd_assemble_rate_code(preamble, nss, rix);
+	}
+
+	hdd_notice("SET_11AX_RATE val %d rix %d preamble %x nss %d",
+	       set_value, rix, preamble, nss);
+
+	ret = wma_cli_set_command(adapter->sessionId,
+				  WMI_VDEV_PARAM_FIXED_RATE,
+				  set_value, VDEV_CMD);
+
+	return ret;
+}
+
 /**
  * __iw_set_commit() - SIOCSIWCOMMIT ioctl handler
  * @dev: device upon which the ioctl was received
@@ -7863,7 +7931,7 @@
 						WMI_RATE_PREAMBLE_OFDM;
 				}
 			}
-			set_value = (preamble << 6) | (nss << 4) | rix;
+			set_value = hdd_assemble_rate_code(preamble, nss, rix);
 		}
 		hdd_info("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d",
 			 set_value, rix, preamble, nss);
@@ -7883,7 +7951,7 @@
 			preamble = WMI_RATE_PREAMBLE_VHT;
 			nss = HT_RC_2_STREAMS_11AC(set_value) - 1;
 
-			set_value = (preamble << 6) | (nss << 4) | rix;
+			set_value = hdd_assemble_rate_code(preamble, nss, rix);
 		}
 		hdd_info("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d",
 			 set_value, rix, preamble, nss);
@@ -8438,6 +8506,9 @@
 		hdd_ctx->config->conc_system_pref = set_value;
 		break;
 	}
+	case WE_SET_11AX_RATE:
+		ret = hdd_set_11ax_rate(pAdapter, set_value, NULL);
+		break;
 	default:
 	{
 		hdd_err("Invalid sub command %d",
@@ -13453,6 +13524,11 @@
 	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
 	 "hostroamdelay"}
 	,
+	{WE_SET_11AX_RATE,
+	 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+	 0,
+	 "set_11ax_rate"}
+	,
 };
 
 const struct iw_handler_def we_handler_def = {