prima: Defer back to back RoC request when sta is connected

If back to back listen received when sta is connected then fw is
not getting enough time to spend on home channel so it leading to
heartbeat failure.

Defering the RoC request if it is received in very less time after
previous RoC is complete.

Change-Id: I7b391b6bd5895b8f816081f96e1f3b5d4a9f5576
CRs-Fixed: 766455
diff --git a/CORE/HDD/src/wlan_hdd_p2p.c b/CORE/HDD/src/wlan_hdd_p2p.c
index 9cd9b9a..f7a082b 100644
--- a/CORE/HDD/src/wlan_hdd_p2p.c
+++ b/CORE/HDD/src/wlan_hdd_p2p.c
@@ -223,6 +223,7 @@
                               pRemainChanCtx->chan_type,
 #endif
                               GFP_KERNEL);
+        pAdapter->lastRocTs = vos_timer_get_system_time();
     }
 
 
@@ -278,12 +279,15 @@
     mutex_lock(&pHddCtx->roc_lock);
     if(cfgState->remain_on_chan_ctx != NULL)
     {
-        hddLog(VOS_TRACE_LEVEL_INFO,
-               "Cancel Existing ROC (cookie=%llu)",
-                cfgState->remain_on_chan_ctx->cookie);
+        if(VOS_TIMER_STATE_RUNNING == vos_timer_getCurrentState(
+                    &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer))
+        {
+            hddLog(VOS_TRACE_LEVEL_INFO,
+                    "Cancel Existing ROC (cookie=%llu)",
+                    cfgState->remain_on_chan_ctx->cookie);
 
-        vos_timer_stop(&cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer);
-
+            vos_timer_stop(&cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer);
+        }
         /* Wait till remain on channel ready indication before issuing cancel
          * remain on channel request, otherwise if remain on channel not
          * received and if the driver issues cancel remain on channel then lim
@@ -437,6 +441,116 @@
     hdd_allow_suspend();
 }
 
+static int wlan_hdd_p2p_start_remain_on_channel(
+        hdd_adapter_t *pAdapter)
+{
+    VOS_STATUS status = VOS_STATUS_SUCCESS;
+    hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+    hdd_adapter_t *pAdapter_temp;
+    v_BOOL_t isGoPresent = VOS_FALSE;
+    hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
+    hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
+    hdd_remain_on_chan_ctx_t *pRemainChanCtx = cfgState->remain_on_chan_ctx;
+    rem_on_channel_request_type_t request_type = pRemainChanCtx->rem_on_chan_request;
+
+    /* Initialize Remain on chan timer */
+    status = vos_timer_init(&pRemainChanCtx->hdd_remain_on_chan_timer,
+            VOS_TIMER_TYPE_SW,
+            wlan_hdd_remain_on_chan_timeout,
+            pAdapter);
+    if (status != VOS_STATUS_SUCCESS)
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+                "%s: Not able to initalize remain_on_chan timer", __func__);
+    }
+    status =  hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+    while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+    {
+        pAdapter_temp = pAdapterNode->pAdapter;
+        if (WLAN_HDD_P2P_GO == pAdapter_temp->device_mode)
+        {
+            isGoPresent = VOS_TRUE;
+        }
+        status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+        pAdapterNode = pNext;
+    }
+    hdd_prevent_suspend();
+    //call sme API to start remain on channel.
+    if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
+            ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
+            ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
+       )
+    {
+        tANI_U8 sessionId = pAdapter->sessionId;
+        //call sme API to start remain on channel.
+        if (eHAL_STATUS_SUCCESS != sme_RemainOnChannel(
+                WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
+                pRemainChanCtx->chan.hw_value, pRemainChanCtx->duration,
+                wlan_hdd_remain_on_channel_callback, pAdapter,
+                (tANI_U8)(request_type == REMAIN_ON_CHANNEL_REQUEST)? TRUE:FALSE))
+        {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                    FL(" RemainOnChannel returned fail"));
+            cfgState->remain_on_chan_ctx = NULL;
+            vos_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer);
+            vos_mem_free (pRemainChanCtx);
+            hdd_allow_suspend();
+            return -EINVAL;
+        }
+
+        if( REMAIN_ON_CHANNEL_REQUEST == request_type)
+        {
+            if( eHAL_STATUS_SUCCESS != sme_RegisterMgmtFrame(
+                        WLAN_HDD_GET_HAL_CTX(pAdapter),
+                        sessionId, (SIR_MAC_MGMT_FRAME << 2) |
+                        (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 ))
+            {
+                hddLog(VOS_TRACE_LEVEL_ERROR,    "sme_RegisterMgmtFrame returned fail");
+            }
+        }
+
+    }
+    else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
+            ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
+            )
+    {
+        //call sme API to start remain on channel.
+        if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
+                    (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+                    pRemainChanCtx->chan.hw_value, pRemainChanCtx->duration,
+                    wlan_hdd_remain_on_channel_callback, pAdapter ))
+
+        {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                    "%s: WLANSAP_RemainOnChannel returned fail", __func__);
+            cfgState->remain_on_chan_ctx = NULL;
+            vos_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer);
+            vos_mem_free (pRemainChanCtx);
+            hdd_allow_suspend();
+            return -EINVAL;
+        }
+
+
+        if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
+                    (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+                    (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
+                    NULL, 0 ))
+        {
+            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                    "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
+            WLANSAP_CancelRemainOnChannel(
+                    (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
+            hdd_allow_suspend();
+            return -EINVAL;
+        }
+
+    }
+
+    pAdapter->is_roc_inprogress = TRUE;
+    return 0;
+}
+
+
 static int wlan_hdd_request_remain_on_channel( struct wiphy *wiphy,
                                    struct net_device *dev,
                                    struct ieee80211_channel *chan,
@@ -449,13 +563,10 @@
     hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
     hdd_remain_on_chan_ctx_t *pRemainChanCtx;
     hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
-    VOS_STATUS vos_status = VOS_STATUS_E_FAILURE;
     hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
-    hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
-    hdd_adapter_t *pAdapter_temp;
-    VOS_STATUS status;
-    v_BOOL_t isGoPresent = VOS_FALSE;
     VOS_STATUS checkReadyInd;
+    hdd_adapter_t *pStaAdapter;
+
     hddLog(VOS_TRACE_LEVEL_INFO, "%s: device_mode = %d",
                                  __func__,pAdapter->device_mode);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
@@ -523,105 +634,31 @@
     pRemainChanCtx->action_pkt_buff.frame_length = 0;
     pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = FALSE;
     pRemainChanCtx->is_pending_roc_cancelled = FALSE;
-    /* Initialize Remain on chan timer */
-    vos_status = vos_timer_init(&pRemainChanCtx->hdd_remain_on_chan_timer,
-                                VOS_TIMER_TYPE_SW,
-                                wlan_hdd_remain_on_chan_timeout,
-                                pAdapter);
-    if (vos_status != VOS_STATUS_SUCCESS)
-    {
-         hddLog(VOS_TRACE_LEVEL_ERROR,
-             "%s: Not able to initalize remain_on_chan timer", __func__);
-    }
-    status =  hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
-    while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
-    {
-        pAdapter_temp = pAdapterNode->pAdapter;
-        if (WLAN_HDD_P2P_GO == pAdapter_temp->device_mode)
-        {
-            isGoPresent = VOS_TRUE;
-        }
-        status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
-        pAdapterNode = pNext;
-    }
-    hdd_prevent_suspend();
+
     INIT_COMPLETION(pAdapter->rem_on_chan_ready_event);
 
-    //call sme API to start remain on channel.
-    if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
-         ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
-         ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode )
-       )
+    if (REMAIN_ON_CHANNEL_REQUEST == request_type)
     {
-        tANI_U8 sessionId = pAdapter->sessionId;
-        //call sme API to start remain on channel.
-        if (eHAL_STATUS_SUCCESS != sme_RemainOnChannel(
-             WLAN_HDD_GET_HAL_CTX(pAdapter), sessionId,
-             chan->hw_value, duration,
-             wlan_hdd_remain_on_channel_callback, pAdapter,
-             (tANI_U8)(request_type == REMAIN_ON_CHANNEL_REQUEST)? TRUE:FALSE))
+        pStaAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
+        if((NULL != pStaAdapter)&&
+                hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR(pStaAdapter)))
         {
-            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                    FL(" RemainOnChannel returned fail"));
-            cfgState->remain_on_chan_ctx = NULL;
-            vos_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer);
-            vos_mem_free (pRemainChanCtx);
-            hdd_allow_suspend();
-            return -EINVAL;
-        }
-
-        if( REMAIN_ON_CHANNEL_REQUEST == request_type)
-        {
-            if( eHAL_STATUS_SUCCESS != sme_RegisterMgmtFrame(
-                                      WLAN_HDD_GET_HAL_CTX(pAdapter),
-                                      sessionId, (SIR_MAC_MGMT_FRAME << 2) |
-                                      (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0 ))
+            if (pAdapter->lastRocTs !=0 &&
+                    ((vos_timer_get_system_time() - pAdapter->lastRocTs )
+                     < pHddCtx->cfg_ini->gP2PListenDeferInterval))
             {
-                hddLog(VOS_TRACE_LEVEL_ERROR,
-                       "sme_RegisterMgmtFrame returned fail");
+                if (pRemainChanCtx->duration > HDD_P2P_MAX_ROC_DURATION)
+                    pRemainChanCtx->duration = HDD_P2P_MAX_ROC_DURATION;
+                schedule_delayed_work(&pAdapter->roc_work,
+                        msecs_to_jiffies(pHddCtx->cfg_ini->gP2PListenDeferInterval));
+                hddLog(VOS_TRACE_LEVEL_INFO, "Defer interval is %hu, pAdapter %p",
+                        pHddCtx->cfg_ini->gP2PListenDeferInterval, pAdapter);
+                return 0;
             }
         }
-
-    }
-    else if ( ( WLAN_HDD_SOFTAP== pAdapter->device_mode ) ||
-              ( WLAN_HDD_P2P_GO == pAdapter->device_mode )
-            )
-    {
-        //call sme API to start remain on channel.
-        if (VOS_STATUS_SUCCESS != WLANSAP_RemainOnChannel(
-                          (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
-                          chan->hw_value, duration,
-                          wlan_hdd_remain_on_channel_callback, pAdapter ))
-
-        {
-           VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                    "%s: WLANSAP_RemainOnChannel returned fail", __func__);
-           cfgState->remain_on_chan_ctx = NULL;
-           vos_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer);
-           vos_mem_free (pRemainChanCtx);
-           hdd_allow_suspend();
-           return -EINVAL;
-        }
-
-
-        if (VOS_STATUS_SUCCESS != WLANSAP_RegisterMgmtFrame(
-                    (WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
-                    (SIR_MAC_MGMT_FRAME << 2) | ( SIR_MAC_MGMT_PROBE_REQ << 4),
-                    NULL, 0 ))
-        {
-            VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                    "%s: WLANSAP_RegisterMgmtFrame returned fail", __func__);
-            WLANSAP_CancelRemainOnChannel(
-                    (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
-            hdd_allow_suspend();
-            return -EINVAL;
-        }
-
     }
 
-    pAdapter->is_roc_inprogress = TRUE;
-    return 0;
-
+    return wlan_hdd_p2p_start_remain_on_channel(pAdapter);
 }
 
 int __wlan_hdd_cfg80211_remain_on_channel( struct wiphy *wiphy,
@@ -2456,3 +2493,11 @@
 
 }
 
+void hdd_p2p_roc_work_queue(struct work_struct *work)
+{
+    hdd_adapter_t *pAdapter = container_of(to_delayed_work(work), hdd_adapter_t, roc_work);
+    hddLog( VOS_TRACE_LEVEL_INFO, FL("%s: "), __func__);
+    wlan_hdd_p2p_start_remain_on_channel(pAdapter);
+    return;
+}
+