wlan: set wificonfiguration(wfc) parameters to firmware

Program the wifi configurations in the firmware using the vendor
commands

We can set the following three parameters using wfc:

* Modulated DTIM
* Average Stats Factor
* Guard Time

* Existing infrastucture is used for setting the modulated DTIM,
  We check if we are presently in BMPS then comeout of BMPS,
  set the requested modulated DTIM and enter BMPS again. If we are
  not in BMPS state, the requested value shall be effective when we
  enter the BMPS state again.

* For Guard Time & Average stats factor new WDI command is sent to
  firmware(WDI_WIFI_CONFIG_REQ) and the status of the response is
  checked in WDI response callback and the message shall be dropped
  in WDA.

Change-Id: I9ebd1daacdb06e88b064936efe86af78c7fbdac4
CRs-Fixed: 924853
diff --git a/CORE/HDD/inc/wlan_hdd_assoc.h b/CORE/HDD/inc/wlan_hdd_assoc.h
index d96e66d..3cad4c0 100644
--- a/CORE/HDD/inc/wlan_hdd_assoc.h
+++ b/CORE/HDD/inc/wlan_hdd_assoc.h
@@ -147,4 +147,6 @@
                                        const tANI_U8 numBss);
 #endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
 
+void iw_full_power_cbfn (void *pContext, eHalStatus status);
+
 #endif
diff --git a/CORE/HDD/inc/wlan_hdd_cfg.h b/CORE/HDD/inc/wlan_hdd_cfg.h
index 9f39771..2a4dfa4 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg.h
@@ -2576,6 +2576,12 @@
 #define CFG_ACTIVE_PASSIVE_CHAN_CONV_MAX  (1)
 #define CFG_ACTIVE_PASSIVE_CHAN_CONV_DEF  (1)
 
+#define CFG_WIFI_CONFIG_ENABLE                  "gEnableWifiConfig"
+#define CFG_WIFI_CONFIG_MIN                          (0)
+#define CFG_WIFI_CONFIG_MAX                          (1)
+#define CFG_WIFI_CONFIG_DEFAULT                      (1)
+
+
 /*--------------------------------------------------------------------------- 
   Type declarations
   -------------------------------------------------------------------------*/ 
@@ -3095,7 +3101,8 @@
    v_BOOL_t                    enableFwrMemDump;
    v_U8_t                      gActivePassiveChCon;
    v_U32_t                     cfgExtScanConcMode;
-   v_U16_t                      rps_mask;
+   v_U16_t                     rps_mask;
+   v_BOOL_t                    fEnableWifiConfig;
 } hdd_config_t;
 
 /*--------------------------------------------------------------------------- 
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 6953a6c..2fe0f9d 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -175,6 +175,10 @@
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST = 66,
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND = 67,
     QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST = 68,
+
+    /* Wi-Fi Configuration subcommands */
+    QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74,
+    QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75,
     QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA = 77,
 
     QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI = 80,
@@ -1077,6 +1081,26 @@
     QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1,
 };
 
+/**
+ * enum qca_wlan_vendor_config: wifi config attr
+ *
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID: invalid config
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM: dynamic dtim
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR: stats avg. factor
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME: guard time
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_LAST: last config
+ * @QCA_WLAN_VENDOR_ATTR_CONFIG_MAX: max config
+ */
+enum qca_wlan_vendor_config {
+    QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID = 0,
+    QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM,
+    QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR,
+    QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME,
+    /* keep last */
+    QCA_WLAN_VENDOR_ATTR_CONFIG_LAST,
+    QCA_WLAN_VENDOR_ATTR_CONFIG_MAX =
+    QCA_WLAN_VENDOR_ATTR_CONFIG_LAST - 1
+};
 
 /* Feature defines */
 #define WIFI_FEATURE_INFRA              0x0001   /* Basic infrastructure mode */
@@ -1101,6 +1125,10 @@
                                                     Concurrency */
 #define WIFI_FEATURE_LINK_LAYER_STATS   0x10000  /* Link layer stats */
 
+/* WIFI CONFIG Parameter defines */
+#define WIFI_CONFIG_SET_AVG_STATS_FACTOR 0x0001  /* Average stats factor */
+#define WIFI_CONFIG_SET_GUARD_TIME      0x0002  /* Guard Time */
+
 /* Add more features here */
 enum qca_wlan_vendor_attr_set_no_dfs_flag
 {
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 465e4ab..2db1653 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -3146,7 +3146,7 @@
 }
 #endif
 
-static void iw_full_power_cbfn (void *pContext, eHalStatus status)
+void iw_full_power_cbfn (void *pContext, eHalStatus status)
 {
     hdd_adapter_t *pAdapter = (hdd_adapter_t *)pContext;
     hdd_context_t *pHddCtx = NULL;
diff --git a/CORE/HDD/src/wlan_hdd_cfg.c b/CORE/HDD/src/wlan_hdd_cfg.c
index f604ec3..b324823 100644
--- a/CORE/HDD/src/wlan_hdd_cfg.c
+++ b/CORE/HDD/src/wlan_hdd_cfg.c
@@ -3446,6 +3446,13 @@
                  CFG_RPS_CPU_MAP_DEFAULT,
                  CFG_RPS_CPU_MAP_MIN,
                  CFG_RPS_CPU_MAP_MAX),
+
+   REG_VARIABLE( CFG_WIFI_CONFIG_ENABLE, WLAN_PARAM_Integer,
+                 hdd_config_t, fEnableWifiConfig,
+                 VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,
+                 CFG_WIFI_CONFIG_DEFAULT,
+                 CFG_WIFI_CONFIG_MIN,
+                 CFG_WIFI_CONFIG_MAX ),
 };
 
 /*
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 47fbe38..07099c6 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -7175,6 +7175,178 @@
     return cfg80211_vendor_cmd_reply(reply_skb);
 }
 
+#define PARAM_WIFICONFIG_MAX QCA_WLAN_VENDOR_ATTR_CONFIG_MAX
+#define PARAM_MODULATED_DTIM QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM
+#define PARAM_STATS_AVG_FACTOR QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR
+#define PARAM_GUARD_TIME QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME
+
+/**
+ * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration
+ * vendor command
+ *
+ * @wiphy: wiphy device pointer
+ * @wdev: wireless device pointer
+ * @data: Vendor command data buffer
+ * @data_len: Buffer length
+ *
+ * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX.
+ *
+ * Return: EOK or other error codes.
+ */
+
+static int __wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
+                            struct wireless_dev *wdev,
+                            const void *data,
+                            int data_len)
+{
+    struct net_device *dev = wdev->netdev;
+    hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+    hdd_context_t *pHddCtx  = wiphy_priv(wiphy);
+    hdd_station_ctx_t *pHddStaCtx;
+    struct nlattr *tb[PARAM_WIFICONFIG_MAX + 1];
+    tpSetWifiConfigParams pReq;
+    eHalStatus status;
+    int ret_val;
+    static const struct nla_policy policy[PARAM_WIFICONFIG_MAX + 1] = {
+                        [PARAM_STATS_AVG_FACTOR] = { .type = NLA_U16 },
+                        [PARAM_MODULATED_DTIM] = { .type = NLA_U32 },
+                       [PARAM_GUARD_TIME] = { .type = NLA_U32},
+    };
+
+    ENTER();
+
+    if (VOS_FTM_MODE == hdd_get_conparam()) {
+        hddLog(LOGE, FL("Command not allowed in FTM mode"));
+        return -EINVAL;
+    }
+
+    ret_val = wlan_hdd_validate_context(pHddCtx);
+    if (ret_val) {
+        return ret_val;
+    }
+
+    pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+
+    if (!hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) {
+                hddLog(LOGE, FL("Not in Connected state!"));
+                return -ENOTSUPP;
+    }
+
+    if (nla_parse(tb, PARAM_WIFICONFIG_MAX, data, data_len, policy)) {
+               hddLog(LOGE, FL("Invalid ATTR"));
+               return -EINVAL;
+    }
+
+    /* check the Wifi Capability */
+    if ( (TRUE != pHddCtx->cfg_ini->fEnableWifiConfig) &&
+         (TRUE != sme_IsFeatureSupportedByFW(WIFI_CONFIG)))
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+               FL("WIFICONFIG not supported by Firmware"));
+        return -EINVAL;
+    }
+
+   pReq = vos_mem_malloc(sizeof(tSetWifiConfigParams));
+
+    if (!pReq) {
+      VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
+             "%s: Not able to allocate memory for tSetWifiConfigParams",
+             __func__);
+       return eHAL_STATUS_E_MALLOC_FAILED;
+   }
+
+   vos_mem_set(pReq, sizeof(tSetWifiConfigParams), 0);
+
+   pReq->sessionId = pAdapter->sessionId;
+   vos_mem_copy( &pReq->bssId, pHddStaCtx->conn_info.bssId, WNI_CFG_BSSID_LEN);
+
+    if (tb[PARAM_MODULATED_DTIM]) {
+       pReq->paramValue = nla_get_u32(
+            tb[PARAM_MODULATED_DTIM]);
+       hddLog(LOG1, FL("Modulated DTIM: pReq->paramValue:%d "),
+                                        pReq->paramValue);
+       pHddCtx->cfg_ini->fMaxLIModulatedDTIM = pReq->paramValue;
+       hdd_set_pwrparams(pHddCtx);
+    if (BMPS == pmcGetPmcState(pHddCtx->hHal)) {
+       hddLog( LOG1, FL("WifiConfig: Requesting FullPower!"));
+
+       sme_RequestFullPower(WLAN_HDD_GET_HAL_CTX(pAdapter),
+                            iw_full_power_cbfn, pAdapter,
+                            eSME_FULL_PWR_NEEDED_BY_HDD);
+       }
+       else
+       {
+            hddLog( LOG1, FL("WifiConfig Not in BMPS state"));
+       }
+    }
+
+    if (tb[PARAM_STATS_AVG_FACTOR]) {
+        pReq->paramType = WIFI_CONFIG_SET_AVG_STATS_FACTOR;
+        pReq->paramValue = nla_get_u16(
+            tb[PARAM_STATS_AVG_FACTOR]);
+        hddLog(LOG1, FL("AVG_STATS_FACTOR pReq->paramType:%d,pReq->paramValue:%d "),
+                                        pReq->paramType, pReq->paramValue);
+        status = sme_set_wificonfig_params(pHddCtx->hHal, pReq);
+
+        if (eHAL_STATUS_SUCCESS != status)
+        {
+            vos_mem_free(pReq);
+            pReq = NULL;
+            ret_val = -EPERM;
+            return ret_val;
+        }
+    }
+
+
+    if (tb[PARAM_GUARD_TIME]) {
+        pReq->paramType = WIFI_CONFIG_SET_GUARD_TIME;
+        pReq->paramValue = nla_get_u32(
+            tb[PARAM_GUARD_TIME]);
+       hddLog(LOG1, FL("GUARD_TIME pReq->paramType:%d,pReq->paramValue:%d "),
+                                        pReq->paramType, pReq->paramValue);
+        status = sme_set_wificonfig_params(pHddCtx->hHal, pReq);
+
+        if (eHAL_STATUS_SUCCESS != status)
+        {
+            vos_mem_free(pReq);
+            pReq = NULL;
+            ret_val = -EPERM;
+            return ret_val;
+        }
+
+    }
+
+    EXIT();
+    return ret_val;
+}
+
+/**
+ * wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration
+ * vendor command
+ *
+ * @wiphy: wiphy device pointer
+ * @wdev: wireless device pointer
+ * @data: Vendor command data buffer
+ * @data_len: Buffer length
+ *
+ * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX.
+ *
+ * Return: EOK or other error codes.
+ */
+static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
+                            struct wireless_dev *wdev,
+                            const void *data,
+                            int data_len)
+{
+    int ret;
+
+    vos_ssr_protect(__func__);
+    ret = __wlan_hdd_cfg80211_wifi_configuration_set(wiphy, wdev,
+                             data, data_len);
+    vos_ssr_unprotect(__func__);
+
+    return ret;
+}
 const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] =
 {
     {
@@ -7412,6 +7584,14 @@
             WIPHY_VENDOR_CMD_NEED_NETDEV |
             WIPHY_VENDOR_CMD_NEED_RUNNING,
         .doit = wlan_hdd_cfg80211_get_link_properties
+    },
+    {
+        .info.vendor_id = QCA_NL80211_VENDOR_ID,
+        .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION,
+        .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+                 WIPHY_VENDOR_CMD_NEED_NETDEV |
+                 WIPHY_VENDOR_CMD_NEED_RUNNING,
+        .doit = wlan_hdd_cfg80211_wifi_configuration_set
     }
 };