SCAN-OFFLOAD: Adding separate SME queue for scan commands.

In concurrent scenarios when scan is issued from the host, the FW will
do the split the scan. In this case the scan is going to take huge time
to complete. Adding a separate SME to queue for scan commands, to avoid
the blocking the SME sme command active list till scan gets complete.

Change-Id: I12e162f69f809e5849a9decaf99d7fd0f1c0015c
CRs-fixed: 500914
diff --git a/CORE/SME/inc/smeInternal.h b/CORE/SME/inc/smeInternal.h
index 9e4f2eb..fbc8dea 100644
--- a/CORE/SME/inc/smeInternal.h
+++ b/CORE/SME/inc/smeInternal.h
@@ -149,6 +149,10 @@
 #ifdef FEATURE_WLAN_LPHB
     void (*pLphbWaitTimeoutCb) (void *pAdapter, void *indParam);
 #endif /* FEATURE_WLAN_LPHB */
+    //pending scan command list
+    tDblLinkList smeScanCmdPendingList;
+    //active scan command list
+    tDblLinkList smeScanCmdActiveList;
 } tSmeStruct, *tpSmeStruct;
 
 
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index 25e7d64..a037ba4 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -15737,6 +15737,16 @@
         return eHAL_STATUS_CSR_WRONG_STATE;
     }
 
+    if ((pMac->fScanOffload) && (pCommand->command == eSmeCommandScan))
+    {
+        csrLLInsertTail(&pMac->sme.smeScanCmdPendingList,
+                        &pCommand->Link, LL_ACCESS_LOCK);
+        // process the command queue...
+        smeProcessPendingQueue(pMac);
+        status = eHAL_STATUS_SUCCESS;
+        goto end;
+    }
+
     //We can call request full power first before putting the command into pending Q
     //because we are holding SME lock at this point.
     status = csrRequestFullPower( pMac, pCommand );
@@ -15751,7 +15761,7 @@
         }
         else
         {
-             //Other commands are waiting for PMC callback, queue the new command to the pending Q
+            //Other commands are waiting for PMC callback, queue the new command to the pending Q
             //no list lock is needed since SME lock is held
             if( !fHighPriority )
             {
@@ -15760,7 +15770,7 @@
             else {
                 csrLLInsertHead( &pMac->roam.roamCmdPendingList, &pCommand->Link, eANI_BOOLEAN_FALSE );
             }
-       }
+        }
     }
     else if( eHAL_STATUS_PMC_PENDING == status )
     {
@@ -15777,10 +15787,11 @@
     }
     else
     {
-        //Not to decrease pMac->roam.sPendingCommands here. Caller will decrease it when it 
+        //Not to decrease pMac->roam.sPendingCommands here. Caller will decrease it when it
         //release the command.
         smsLog( pMac, LOGE, FL( "  cannot queue command %d" ), pCommand->command );
     }
+end:
     return ( status );
 }
 eHalStatus csrRoamUpdateAPWPSIE( tpAniSirGlobal pMac, tANI_U32 sessionId, tSirAPWPSIEs* pAPWPSIES )
diff --git a/CORE/SME/src/csr/csrApiScan.c b/CORE/SME/src/csr/csrApiScan.c
index 639ff55..f665010 100644
--- a/CORE/SME/src/csr/csrApiScan.c
+++ b/CORE/SME/src/csr/csrApiScan.c
@@ -884,7 +884,11 @@
                         {
                             //Start process the command
 #ifdef WLAN_AP_STA_CONCURRENCY
-                            status = csrQueueScanRequest(pMac, p11dScanCmd);
+                            if (!pMac->fScanOffload)
+                                status = csrQueueScanRequest(pMac, p11dScanCmd);
+                            else
+                                status = csrQueueSmeCommand(pMac, p11dScanCmd,
+                                                            eANI_BOOLEAN_FALSE);
 #else
                             status = csrQueueSmeCommand(pMac, p11dScanCmd, eANI_BOOLEAN_FALSE);
 #endif                   
@@ -920,7 +924,11 @@
                 {
                     //Start process the command
 #ifdef WLAN_AP_STA_CONCURRENCY
-                    status = csrQueueScanRequest(pMac,pScanCmd); 
+                    if (!pMac->fScanOffload)
+                        status = csrQueueScanRequest(pMac,pScanCmd);
+                    else
+                        status = csrQueueSmeCommand(pMac, pScanCmd,
+                                                    eANI_BOOLEAN_FALSE);
 #else
                     status = csrQueueSmeCommand(pMac, pScanCmd, eANI_BOOLEAN_FALSE);                   
 #endif
@@ -4128,7 +4136,10 @@
     tANI_BOOLEAN fRemoveCommand = eANI_BOOLEAN_TRUE;
     tANI_BOOLEAN fSuccess;
 
-    pEntry = csrLLPeekHead( &pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK );
+    if (pMac->fScanOffload)
+        pEntry = csrLLPeekHead(&pMac->sme.smeScanCmdActiveList, LL_ACCESS_LOCK);
+    else
+        pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
 
     if ( pEntry )
     {
@@ -4725,6 +4736,9 @@
     }
 
 #ifdef WLAN_AP_STA_CONCURRENCY
+    if (pMac->fScanOffload)
+        return fRet;
+
     if (!csrLLIsListEmpty( &pMac->scan.scanCmdPendingList, LL_ACCESS_LOCK ))
     {
         /* Pending scan commands in the list because the previous scan command
@@ -4733,21 +4747,21 @@
          *
          * Start timer to trigger processing of the next scan command.
          * NOTE for LFR:
-         * Do not split scans if no concurrent infra connections are 
+         * Do not split scans if no concurrent infra connections are
          * active and if the scan is a BG scan triggered by LFR (OR)
          * any scan if LFR is in the middle of a BG scan. Splitting
          * the scan is delaying the time it takes for LFR to find
          * candidates and resulting in disconnects.
          */
-        if ( (csrIsStaSessionConnected(pMac) && 
+        if ( (csrIsStaSessionConnected(pMac) &&
 #ifdef FEATURE_WLAN_LFR
                     (csrIsConcurrentInfraConnected(pMac) ||
                      ((pCommand->u.scanCmd.reason != eCsrScanBgScan) &&
-                      (pMac->roam.neighborRoamInfo.neighborRoamState != 
+                      (pMac->roam.neighborRoamInfo.neighborRoamState !=
                        eCSR_NEIGHBOR_ROAM_STATE_CFG_CHAN_LIST_SCAN))) &&
 #endif
                     (pCommand->u.scanCmd.u.scanRequest.p2pSearch != 1)) ||
-             (csrIsP2pSessionConnected(pMac)) )
+                (csrIsP2pSessionConnected(pMac)) )
         {
             /* if active connected sessions present then continue to split scan
              * with specified interval between consecutive scans */
@@ -4788,7 +4802,11 @@
     tANI_BOOLEAN fRemoveCommand = eANI_BOOLEAN_TRUE;
     eCsrScanReason reason = eCsrScanOther;
 
-    pEntry = csrLLPeekHead( &pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK );
+    if (pMac->fScanOffload)
+        pEntry = csrLLPeekHead(&pMac->sme.smeScanCmdActiveList,
+                               LL_ACCESS_LOCK);
+    else
+        pEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
 
     if ( pEntry )
     {
@@ -5375,10 +5393,26 @@
     tANI_U32 len = 0;
 
     // Transition to Scanning state...
-    for( i = 0; i < CSR_ROAM_SESSION_MAX; i++ )
+    if (!pMac->fScanOffload)
     {
-      pCommand->u.scanCmd.lastRoamState[i] = csrRoamStateChange( pMac, eCSR_ROAMING_STATE_SCANNING, i);
-      smsLog( pMac, LOG3, "starting SCAN command from %d state.... reason is %d", pCommand->u.scanCmd.lastRoamState[i], pCommand->u.scanCmd.reason );
+        for( i = 0; i < CSR_ROAM_SESSION_MAX; i++ )
+        {
+            pCommand->u.scanCmd.lastRoamState[i] =
+                csrRoamStateChange( pMac, eCSR_ROAMING_STATE_SCANNING, i);
+            smsLog( pMac, LOG3, "starting SCAN command from %d state...."
+                    " reason is %d", pCommand->u.scanCmd.lastRoamState[i],
+                    pCommand->u.scanCmd.reason );
+        }
+    }
+    else
+    {
+        pCommand->u.scanCmd.lastRoamState[pCommand->sessionId] =
+            csrRoamStateChange(pMac, eCSR_ROAMING_STATE_SCANNING,
+                               pCommand->sessionId);
+        smsLog( pMac, LOG3,
+                "starting SCAN command from %d state.... reason is %d",
+                pCommand->u.scanCmd.lastRoamState[pCommand->sessionId],
+                pCommand->u.scanCmd.reason );
     }
 
     switch(pCommand->u.scanCmd.reason)
@@ -6568,22 +6602,44 @@
 void csrReleaseScanCommand(tpAniSirGlobal pMac, tSmeCmd *pCommand, eCsrScanStatus scanStatus)
 {
     eCsrScanReason reason = pCommand->u.scanCmd.reason;
-    tANI_U32 i;
-    for( i = 0; i < CSR_ROAM_SESSION_MAX; i++ )
+    tANI_BOOLEAN status;
+
+    if (!pMac->fScanOffload)
     {
-         csrRoamStateChange( pMac, pCommand->u.scanCmd.lastRoamState[i], i);
+        tANI_U32 i;
+        for(i = 0; i < CSR_ROAM_SESSION_MAX; i++)
+            csrRoamStateChange(pMac, pCommand->u.scanCmd.lastRoamState[i], i);
+    }
+    else
+    {
+        csrRoamStateChange(pMac,
+                pCommand->u.scanCmd.lastRoamState[pCommand->sessionId],
+                pCommand->sessionId);
     }
 
-        csrScanCallCallback(pMac, pCommand, scanStatus);
+    csrScanCallCallback(pMac, pCommand, scanStatus);
 
     smsLog(pMac, LOG3, "   Remove Scan command reason = %d", reason);
-    if( csrLLRemoveEntry( &pMac->sme.smeCmdActiveList, &pCommand->Link, LL_ACCESS_LOCK ) )
+    if (pMac->fScanOffload)
+    {
+        status = csrLLRemoveEntry(&pMac->sme.smeScanCmdActiveList,
+                                  &pCommand->Link, LL_ACCESS_LOCK);
+    }
+    else
+    {
+        status = csrLLRemoveEntry(&pMac->sme.smeCmdActiveList,
+                                  &pCommand->Link, LL_ACCESS_LOCK);
+    }
+
+    if(status)
     {
         csrReleaseCommandScan( pMac, pCommand );
     }
     else
     {
-        smsLog(pMac, LOGE, " ********csrReleaseScanCommand cannot release command reason %d", pCommand->u.scanCmd.reason );
+        smsLog(pMac, LOGE,
+                " ********csrReleaseScanCommand cannot release command reason %d",
+                pCommand->u.scanCmd.reason );
     }
 }
 
diff --git a/CORE/SME/src/sme_common/sme_Api.c b/CORE/SME/src/sme_common/sme_Api.c
index 2660b90..a3a19fd 100644
--- a/CORE/SME/src/sme_common/sme_Api.c
+++ b/CORE/SME/src/sme_common/sme_Api.c
@@ -162,30 +162,49 @@
 {
     eHalStatus status;
     tSmeCmd *pCmd;
+    tANI_U32 cmd_idx;
 
     pMac->sme.totalSmeCmd = SME_TOTAL_COMMAND;
-    if(HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd, &pMac->sme.smeCmdActiveList)))
-    {
-        if(HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd, &pMac->sme.smeCmdPendingList)))
-        {
-            if(HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd, &pMac->sme.smeCmdFreeList)))
-            {
-                status = palAllocateMemory(pMac->hHdd, (void **)&pCmd, sizeof(tSmeCmd) * pMac->sme.totalSmeCmd);
-                if(HAL_STATUS_SUCCESS(status))
-                {
-                    tANI_U32 c;
+    if (!HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd,
+                           &pMac->sme.smeCmdActiveList)))
+       goto end;
 
-                    palZeroMemory(pMac->hHdd, pCmd, sizeof(tSmeCmd) * pMac->sme.totalSmeCmd);
-                    pMac->sme.pSmeCmdBufAddr = pCmd;
-                    for(c = 0; c < pMac->sme.totalSmeCmd; c++)
-                    {
-                        csrLLInsertTail(&pMac->sme.smeCmdFreeList, &pCmd[c].Link, LL_ACCESS_LOCK);
-                    }
-                }
-            }
-        }
+    if (!HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd,
+                           &pMac->sme.smeCmdPendingList)))
+       goto end;
+
+    if (!HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd,
+                           &pMac->sme.smeScanCmdActiveList)))
+       goto end;
+
+    if (!HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd,
+                                            &pMac->sme.smeScanCmdPendingList)))
+       goto end;
+
+    if (!HAL_STATUS_SUCCESS(status = csrLLOpen(pMac->hHdd,
+                                             &pMac->sme.smeCmdFreeList)))
+       goto end;
+
+    status = palAllocateMemory(pMac->hHdd,
+                               (void **)&pCmd,
+                               sizeof(tSmeCmd) * pMac->sme.totalSmeCmd);
+    if (!HAL_STATUS_SUCCESS(status))
+       goto end;
+
+    palZeroMemory(pMac->hHdd, pCmd,
+                  sizeof(tSmeCmd) * pMac->sme.totalSmeCmd);
+    pMac->sme.pSmeCmdBufAddr = pCmd;
+    for (cmd_idx = 0; cmd_idx < pMac->sme.totalSmeCmd; cmd_idx++)
+    {
+        csrLLInsertTail(&pMac->sme.smeCmdFreeList,
+                        &pCmd[cmd_idx].Link, LL_ACCESS_LOCK);
     }
 
+end:
+    if (!HAL_STATUS_SUCCESS(status))
+       smsLog(pMac, LOGE, "failed to initialize sme command list:%d\n",
+              status);
+
     return (status);
 }
 
@@ -217,6 +236,8 @@
     //release any out standing commands back to free command list
     smeReleaseCmdList(pMac, &pMac->sme.smeCmdPendingList);
     smeReleaseCmdList(pMac, &pMac->sme.smeCmdActiveList);
+    smeReleaseCmdList(pMac, &pMac->sme.smeScanCmdPendingList);
+    smeReleaseCmdList(pMac, &pMac->sme.smeScanCmdActiveList);
 }
 
 void purgeSmeSessionCmdList(tpAniSirGlobal pMac, tANI_U32 sessionId)
@@ -268,6 +289,8 @@
     purgeSmeCmdList(pMac);
     csrLLClose(&pMac->sme.smeCmdPendingList);
     csrLLClose(&pMac->sme.smeCmdActiveList);
+    csrLLClose(&pMac->sme.smeScanCmdPendingList);
+    csrLLClose(&pMac->sme.smeScanCmdActiveList);
     csrLLClose(&pMac->sme.smeCmdFreeList);
 
     status = vos_lock_acquire(&pMac->sme.lkSmeGlobalLock);
@@ -512,7 +535,119 @@
     }
 }
 
+tListElem *csrGetCmdToProcess(tpAniSirGlobal pMac, tDblLinkList *pList,
+                              tANI_U8 sessionId, tANI_BOOLEAN fInterlocked)
+{
+    tListElem *pCurEntry = NULL;
+    tSmeCmd *pCommand;
 
+    /* Go through the list and return the command whose session id is not
+     * matching with the current ongoing scan cmd sessionId */
+    pCurEntry = csrLLPeekHead( pList, LL_ACCESS_LOCK );
+    while (pCurEntry)
+    {
+        pCommand = GET_BASE_ADDR(pCurEntry, tSmeCmd, Link);
+        if (pCommand->sessionId != sessionId)
+        {
+            smsLog(pMac, LOG1, "selected the command with different sessionId");
+            return pCurEntry;
+        }
+
+        pCurEntry = csrLLNext(pList, pCurEntry, fInterlocked);
+    }
+
+    smsLog(pMac, LOG1, "No command pending with different sessionId");
+    return NULL;
+}
+
+tANI_BOOLEAN smeProcessScanQueue(tpAniSirGlobal pMac)
+{
+    tListElem *pEntry;
+    tSmeCmd *pCommand;
+    tListElem *pSmeEntry;
+    tSmeCmd *pSmeCommand;
+    tANI_BOOLEAN status = eANI_BOOLEAN_TRUE;
+
+    csrLLLock( &pMac->sme.smeScanCmdActiveList );
+    if (csrLLIsListEmpty( &pMac->sme.smeScanCmdActiveList,
+                LL_ACCESS_NOLOCK ))
+    {
+        if (!csrLLIsListEmpty(&pMac->sme.smeScanCmdPendingList,
+                    LL_ACCESS_LOCK))
+        {
+            pEntry = csrLLPeekHead( &pMac->sme.smeScanCmdPendingList,
+                    LL_ACCESS_LOCK );
+            if (pEntry)
+            {
+                pCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link );
+                //We cannot execute any command in wait-for-key state until setKey is through.
+                if (CSR_IS_WAIT_FOR_KEY( pMac, pCommand->sessionId))
+                {
+                    if (!CSR_IS_SET_KEY_COMMAND(pCommand))
+                    {
+                        smsLog(pMac, LOGE,
+                                "  Cannot process command(%d) while waiting for key",
+                                pCommand->command);
+                        status = eANI_BOOLEAN_FALSE;
+                        goto end;
+                    }
+                }
+
+                if ((!csrLLIsListEmpty(&pMac->sme.smeCmdActiveList,
+                                       LL_ACCESS_LOCK )))
+                {
+                    pSmeEntry = csrLLPeekHead(&pMac->sme.smeCmdActiveList,
+                                              LL_ACCESS_LOCK);
+                    if (pEntry)
+                    {
+                       pSmeCommand = GET_BASE_ADDR(pEntry, tSmeCmd,
+                                                   Link) ;
+
+                       /* if scan is running on one interface and SME recei
+                          ves the next command on the same interface then
+                          dont the allow the command to be queued to
+                          smeCmdPendingList. If next scan is allowed on
+                          the same interface the CSR state machine will
+                          get screwed up. */
+                          if (pSmeCommand->sessionId == pCommand->sessionId)
+                          {
+                              status = eANI_BOOLEAN_FALSE;
+                              goto end;
+                          }
+                    }
+                }
+                if ( csrLLRemoveEntry( &pMac->sme.smeScanCmdPendingList,
+                            pEntry, LL_ACCESS_LOCK ) )
+                {
+                    csrLLInsertHead( &pMac->sme.smeScanCmdActiveList,
+                            &pCommand->Link, LL_ACCESS_NOLOCK );
+
+                    switch (pCommand->command)
+                    {
+                        case eSmeCommandScan:
+                            smsLog(pMac, LOG1,
+                                    " Processing scan offload command ");
+                            csrProcessScanCommand( pMac, pCommand );
+                            break;
+                        default:
+                            smsLog(pMac, LOGE,
+                                    " Something wrong, wrong command enqueued"
+                                    " to smeScanCmdPendingList");
+                            pEntry = csrLLRemoveHead(
+                                    &pMac->sme.smeScanCmdActiveList,
+                                    LL_ACCESS_NOLOCK );
+                            pCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link );
+                            smeReleaseCommand( pMac, pCommand );
+                            break;
+                    }
+                }
+            }
+        }
+    }
+end:
+    csrLLUnlock(&pMac->sme.smeScanCmdActiveList);
+    return status;
+}
 
 tANI_BOOLEAN smeProcessCommand( tpAniSirGlobal pMac )
 {
@@ -520,6 +655,8 @@
     eHalStatus status = eHAL_STATUS_SUCCESS;
     tListElem *pEntry;
     tSmeCmd *pCommand;
+    tListElem *pSmeEntry;
+    tSmeCmd *pSmeCommand;
     eSmeCommandType pmcCommand = eSmeNoCommand;
 
     // if the ActiveList is empty, then nothing is active so we can process a
@@ -530,11 +667,36 @@
     {
         if(!csrLLIsListEmpty(&pMac->sme.smeCmdPendingList, LL_ACCESS_LOCK))
         {
+            /* If scan command is pending in the smeScanCmdActive list
+             * then pick the command from smeCmdPendingList which is
+             * not matching with the scan command session id.
+             * At any point of time only one command will be allowed
+             * on a single session. */
+            if ((pMac->fScanOffload) &&
+                    (!csrLLIsListEmpty(&pMac->sme.smeScanCmdActiveList,
+                                       LL_ACCESS_LOCK)))
+            {
+                pSmeEntry = csrLLPeekHead(&pMac->sme.smeScanCmdActiveList,
+                        LL_ACCESS_LOCK);
+                if (pSmeEntry)
+                {
+                    pSmeCommand = GET_BASE_ADDR(pSmeEntry, tSmeCmd, Link);
+
+                    pEntry = csrGetCmdToProcess(pMac,
+                            &pMac->sme.smeCmdPendingList,
+                            pSmeCommand->sessionId,
+                            LL_ACCESS_LOCK);
+                    goto sme_process_cmd;
+                }
+            }
+
             //Peek the command
             pEntry = csrLLPeekHead( &pMac->sme.smeCmdPendingList, LL_ACCESS_LOCK );
+sme_process_cmd:
             if( pEntry )
             {
                 pCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link );
+
                 //We cannot execute any command in wait-for-key state until setKey is through.
                 if( CSR_IS_WAIT_FOR_KEY( pMac, pCommand->sessionId ) )
                 {
@@ -542,7 +704,8 @@
                     {
                         csrLLUnlock( &pMac->sme.smeCmdActiveList );
                         smsLog(pMac, LOGE, "  Cannot process command(%d) while waiting for key", pCommand->command);
-                        return ( eANI_BOOLEAN_FALSE );
+                        fContinue = eANI_BOOLEAN_FALSE;
+                        goto sme_process_scan_queue;
                     }
                 }
                 pmcCommand = smeIsFullPowerNeeded( pMac, pCommand );
@@ -555,7 +718,8 @@
                     }
                     csrLLUnlock( &pMac->sme.smeCmdActiveList );
                     //tell caller to continue
-                    return (eANI_BOOLEAN_TRUE);
+                    fContinue = eANI_BOOLEAN_TRUE;
+                    goto sme_process_scan_queue;
                 }
                 else if( eSmeNoCommand != pmcCommand )
                 {
@@ -594,7 +758,7 @@
                         //Let it retry
                         fContinue = eANI_BOOLEAN_TRUE;
                     }
-                    return fContinue;
+                    goto sme_process_scan_queue;
                 }
                 if ( csrLLRemoveEntry( &pMac->sme.smeCmdPendingList, pEntry, LL_ACCESS_LOCK ) )
                 {
@@ -856,6 +1020,10 @@
         csrLLUnlock( &pMac->sme.smeCmdActiveList );
     }
 
+sme_process_scan_queue:
+    if (pMac->fScanOffload && !(smeProcessScanQueue(pMac)))
+        fContinue = eANI_BOOLEAN_FALSE;
+
     return ( fContinue );
 }