wlan: Add callback handler for wlan suspend

Currently control reaches to caller after posting a message to WDA
in wlan suspend. In some cases it may be possible that message is
still in processing and system goes to sleep since hdd will return
due to non blocking call.

Add callback API to wait in hdd until message is posted to smd.

Change-Id: Ibd1cf138d683037a56c14b8b390d44a9a6b8803e
CRs-Fixed: 1106499
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index e52d7ae..00d5e77 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -1113,6 +1113,9 @@
    struct completion ibss_peer_info_comp;
 #endif /* WLAN_FEATURE_RMC */
 
+   /* completion variable for wlan suspend */
+   struct completion wlan_suspend_comp_var;
+
    /* Track whether the linkup handling is needed  */
    v_BOOL_t isLinkUpSvcNeeded;
 
diff --git a/CORE/HDD/src/wlan_hdd_early_suspend.c b/CORE/HDD/src/wlan_hdd_early_suspend.c
index a61b3c1..dd1a4d9 100644
--- a/CORE/HDD/src/wlan_hdd_early_suspend.c
+++ b/CORE/HDD/src/wlan_hdd_early_suspend.c
@@ -1472,6 +1472,26 @@
     }
 }
 
+/**
+ * hdd_suspend_ind_callback: This API will set completion event for suspend
+ * @pAdapter: hdd_adapter_t
+ * @status: suspend status
+ *
+ * Return: none
+ */
+static void hdd_suspend_ind_callback(void *context, VOS_STATUS status)
+{
+    hdd_adapter_t *adapter = (hdd_adapter_t *)context;
+    if (NULL == adapter)
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+               "%s: HDD adapter is NULL",__func__);
+        return;
+    }
+    hddLog(VOS_TRACE_LEVEL_INFO, FL("suspend status %d"), status);
+    complete(&adapter->wlan_suspend_comp_var);
+}
+
 static void hdd_conf_suspend_ind(hdd_context_t* pHddCtx,
                                  hdd_adapter_t *pAdapter)
 {
@@ -1517,6 +1537,8 @@
         wlanSuspendParam->configuredMcstBcstFilterSetting =
             pHddCtx->configuredMcastBcastFilter;
 
+        wlanSuspendParam->wlan_sus_callback = hdd_suspend_ind_callback;
+        wlanSuspendParam->context = pAdapter;
         /* mc add list cfg item configuration in fwr */
         hdd_mc_addr_list_cfg_config(pHddCtx, true);
 
@@ -1593,7 +1615,7 @@
 {
    hdd_context_t *pHddCtx = NULL;
    v_CONTEXT_t pVosContext = NULL;
-
+   long ret;
    VOS_STATUS status;
    hdd_adapter_t *pAdapter = NULL;
    hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
@@ -1677,9 +1699,17 @@
        }
 #endif
 
+       INIT_COMPLETION(pAdapter->wlan_suspend_comp_var);
        /*Suspend notification sent down to driver*/
        hdd_conf_suspend_ind(pHddCtx, pAdapter);
-
+       ret = wait_for_completion_interruptible_timeout(
+                   &pAdapter->wlan_suspend_comp_var,
+                   msecs_to_jiffies(WLAN_WAIT_TIME_FULL_PWR));
+       if (0 >= ret)
+       {
+          hddLog(VOS_TRACE_LEVEL_ERROR, "%s:wait on suspend failed %ld",
+                 __func__, ret);
+       }
        status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
        pAdapterNode = pNext;
    }
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 3876065..d1c3687 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -8822,7 +8822,6 @@
    if(VOS_STATUS_SUCCESS == status)
    {
       wlan_hdd_set_concurrency_mode(pHddCtx, session_type);
-
       //Initialize the WoWL service
       if(!hdd_init_wowl(pAdapter))
       {
@@ -14843,6 +14842,7 @@
         init_completion(&pAdapter->hdd_set_batch_scan_req_var);
         init_completion(&pAdapter->hdd_get_batch_scan_req_var);
 #endif
+        init_completion(&pAdapter->wlan_suspend_comp_var);
 
         return;
 }
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 5cc1b03..29107ae 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -3758,9 +3758,13 @@
     tANI_U8   psSelection;
 }tSirNoAParam, *tpSirNoAParam;
 
+typedef void(*wlan_suspend_req_cb)(void *ptr, VOS_STATUS status);
+
 typedef struct sSirWlanSuspendParam
 {
     tANI_U8 configuredMcstBcstFilterSetting;
+    wlan_suspend_req_cb wlan_sus_callback;
+    void *context;
 }tSirWlanSuspendParam,*tpSirWlanSuspendParam;
 
 typedef struct sSirWlanResumeParam
diff --git a/CORE/WDA/inc/wlan_qct_wda.h b/CORE/WDA/inc/wlan_qct_wda.h
index 1c67f7e..1b77fbf 100644
--- a/CORE/WDA/inc/wlan_qct_wda.h
+++ b/CORE/WDA/inc/wlan_qct_wda.h
@@ -385,6 +385,8 @@
 typedef void (*WDA_txFailIndCallback)(tANI_U8 *, tANI_U8);
 #endif /* WLAN_FEATURE_RMC */
 
+typedef void (*WDA_suspend_req_callback)(tANI_U8 *, tANI_U8);
+
 typedef struct
 {
    tANI_U16 ucValidStaIndex ;
diff --git a/CORE/WDA/src/wlan_qct_wda.c b/CORE/WDA/src/wlan_qct_wda.c
index 22b00dc..848761a 100644
--- a/CORE/WDA/src/wlan_qct_wda.c
+++ b/CORE/WDA/src/wlan_qct_wda.c
@@ -11519,6 +11519,55 @@
    VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
                                           "<------ %s " ,__func__);
 }
+
+/**
+ * WDA_ProcessWlanSuspendIndCallback: callback API for WDA_ProcessWlanSuspendInd
+ * @wdiStatus: wdi status
+ * @pUserData: suspend params
+ *
+ * Return: None
+ */
+void WDA_ProcessWlanSuspendIndCallback(WDI_Status wdiStatus, void* pUserData)
+{
+   tWDA_ReqParams *pWdaParams = (tWDA_ReqParams *)pUserData;
+   tSirWlanSuspendParam *pWlanSuspendParam;
+
+   VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
+              "<------ %s, wdiStatus: %d", __func__, wdiStatus);
+
+   if(NULL == pWdaParams)
+   {
+      VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                 "%s: pWdaParams received NULL", __func__);
+      return;
+   }
+
+   pWlanSuspendParam = (tSirWlanSuspendParam *)pWdaParams->wdaMsgParam;
+   if (pWlanSuspendParam == NULL)
+   {
+      VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                 "%s: suspend params NULL", __func__);
+      vos_mem_free(pWdaParams);
+      return;
+   }
+   if (pWlanSuspendParam->wlan_sus_callback)
+   {
+      pWlanSuspendParam->wlan_sus_callback(pWlanSuspendParam->context,
+                                       CONVERT_WDI2VOS_STATUS(wdiStatus));
+   }
+   else
+   {
+      VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+          "%s: wlan suspend callback is NULL", __func__);
+   }
+   if (pWdaParams->wdaMsgParam) {
+       vos_mem_free(pWdaParams->wdaMsgParam);
+       pWdaParams->wdaMsgParam = NULL;
+   }
+   vos_mem_free(pWdaParams);
+   return;
+}
+
 /*
  * FUNCTION: WDA_ProcessWlanSuspendInd
  * 
@@ -11528,12 +11577,22 @@
 {
    WDI_Status wdiStatus;
    WDI_SuspendParamsType wdiSuspendParams;
+   tWDA_ReqParams *pWdaParams;
+
    VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO,
                                           "------> %s " ,__func__);
    wdiSuspendParams.wdiSuspendParams.ucConfiguredMcstBcstFilterSetting =
                           pWlanSuspendParam->configuredMcstBcstFilterSetting;
-   wdiSuspendParams.wdiReqStatusCB = WDA_WdiIndicationCallback;
-   wdiSuspendParams.pUserData = pWDA;
+   wdiSuspendParams.wdiReqStatusCB = WDA_ProcessWlanSuspendIndCallback;
+
+   pWdaParams = (tWDA_ReqParams *)vos_mem_malloc(sizeof(tWDA_ReqParams));
+   if (!pWdaParams)
+       VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
+                                          "%s memory allocation failed" ,__func__);
+   pWdaParams->pWdaContext = pWDA;
+   pWdaParams->wdaMsgParam = pWlanSuspendParam;
+   wdiSuspendParams.pUserData = pWdaParams;
+
    VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_INFO, "%s: %d" ,__func__, pWlanSuspendParam->configuredMcstBcstFilterSetting);
    wdiStatus = WDI_HostSuspendInd(&wdiSuspendParams);
    if(WDI_STATUS_PENDING == wdiStatus)
@@ -11546,7 +11605,6 @@
       VOS_TRACE( VOS_MODULE_ID_WDA, VOS_TRACE_LEVEL_ERROR,
               "Failure in %s:%d ",__func__,__LINE__ );
    }
-   vos_mem_free(pWlanSuspendParam);
    return CONVERT_WDI2VOS_STATUS(wdiStatus) ;
 }
 
diff --git a/CORE/WDI/CP/src/wlan_qct_wdi.c b/CORE/WDI/CP/src/wlan_qct_wdi.c
index 1938155..6de2e84 100644
--- a/CORE/WDI/CP/src/wlan_qct_wdi.c
+++ b/CORE/WDI/CP/src/wlan_qct_wdi.c
@@ -23270,6 +23270,7 @@
        */
       pWDICtx->wdiReqStatusCB( ((uStatus != eWLAN_PAL_STATUS_SUCCESS) && (uStatus != eWLAN_PAL_STATUS_E_RESOURCES)) ? WDI_STATUS_E_FAILURE: WDI_STATUS_SUCCESS,
                                pWDICtx->pReqStatusUserData);
+      pWDICtx->wdiReqStatusCB = NULL;
    }
 
    /*If sending of the message failed - it is considered catastrophic and