예제 #1
0
/**
 * \fn     txnQ_SelectTxn
 * \brief  Select transaction to send
 *
 * Called from txnQ_RunScheduler() which is protected in critical section.
 * Select the next enabled transaction by priority.
 *
 * \note
 * \param  pTxnQ - The module's object
 * \return The selected transaction to send (NULL if none available)
 * \sa
 */
static TTxnStruct *txnQ_SelectTxn (TTxnQObj *pTxnQ)
{
	TTxnStruct *pSelectedTxn;
	TI_UINT32   uFunc;
	TI_UINT32   uPrio;

#ifdef TI_DBG
	/* If within Tx aggregation, dequeue Txn from same queue, and if not NULL return it */
	if (pTxnQ->pAggregQueue) {
		pSelectedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->pAggregQueue);
		if (pSelectedTxn != NULL) {
			/* If aggregation ended, reset the aggregation-queue pointer */
			if (TXN_PARAM_GET_AGGREGATE(pSelectedTxn) == TXN_AGGREGATE_OFF) {
				pTxnQ->pAggregQueue = NULL;
			}
			return pSelectedTxn;
		}
		return NULL;
	}
#endif

	/* For all functions, if single-step Txn waiting, return it (sent even if function is stopped) */
	for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++) {
		pSelectedTxn = pTxnQ->aFuncInfo[uFunc].pSingleStep;
		if (pSelectedTxn != NULL) {
			pTxnQ->aFuncInfo[uFunc].pSingleStep = NULL;
			return pSelectedTxn;
		}
	}

	/* For all priorities from high to low */
	for (uPrio = 0; uPrio < MAX_PRIORITY; uPrio++) {
		/* For all functions */
		for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++) {
			/* If function running and uses this priority */
			if (pTxnQ->aFuncInfo[uFunc].eState == FUNC_STATE_RUNNING  &&
			        pTxnQ->aFuncInfo[uFunc].uNumPrios > uPrio) {
				/* Dequeue Txn from current func and priority queue, and if not NULL return it */
				pSelectedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFunc][uPrio]);
				if (pSelectedTxn != NULL) {
#ifdef TI_DBG
					/* If aggregation begins, save the aggregation-queue pointer to ensure continuity */
					if (TXN_PARAM_GET_AGGREGATE(pSelectedTxn) == TXN_AGGREGATE_ON) {
						pTxnQ->pAggregQueue = pTxnQ->aTxnQueues[uFunc][uPrio];
					}
#endif
					return pSelectedTxn;
				}
			}
		}
	}

	/* If no transaction was selected, return NULL */
	return NULL;
}
/** 
 * \fn     tmr_HandleExpiry
 * \brief  Handles queued expiry events in driver context
 * 
 * This is the Timer module's callback that is registered to the ContextEngine module to be invoked
 *   from the driver task (after requested by tmr_GetExpiry through context_RequestSchedule ()).
 * It dequeues all expiry events from the queue that correlates to the current driver state,
 *   and calls their users callbacks.
 * 
 * \note   
 * \param  hTimerModule - The module object
 * \return void
 * \sa     tmr_GetExpiry
 */ 
void tmr_HandleExpiry (TI_HANDLE hTimerModule)
{
    TTimerModule *pTimerModule = (TTimerModule *)hTimerModule; /* The timer module handle */
    TTimerInfo   *pTimerInfo;      /* The timer handle */     
    TI_BOOL       bTwdInitOccured; /* Indicates if TWD init occured since timer start */

    if (!pTimerModule)
    {
        WLAN_OS_REPORT (("tmr_HandleExpiry(): ERROR - NULL timer!\n"));
        return;
    }

    while (1)
    {
        /* Enter critical section */
        context_EnterCriticalSection (pTimerModule->hContext);
    
        /* If current driver state is Operational, dequeue timer object from Operational-queue */
        if (pTimerModule->bOperState)
        {
            pTimerInfo = (TTimerInfo *) que_Dequeue (pTimerModule->hOperQueue);
        }
    
        /* Else (driver state is NOT-Operational), dequeue timer object from Init-queue */
        else
        {
            pTimerInfo = (TTimerInfo *) que_Dequeue (pTimerModule->hInitQueue);
        }
    
        /* Leave critical section */
        context_LeaveCriticalSection (pTimerModule->hContext);

        /* If no more objects in queue, exit */
        if (!pTimerInfo) 
        {
            return;  /** EXIT Point **/
        }

        /* If current TWD-Init-Count is different than when the timer was started, Init occured. */
        bTwdInitOccured = (pTimerModule->uTwdInitCount != pTimerInfo->uTwdInitCountWhenStarted);

        /* Call specific timer callback function */
        pTimerInfo->fExpiryCbFunc (pTimerInfo->hExpiryCbHndl, bTwdInitOccured);

        /* If the expired timer is periodic, start it again. */
        if (pTimerInfo->bPeriodic) 
        {
            tmr_StartTimer ((TI_HANDLE)pTimerInfo,
                            pTimerInfo->fExpiryCbFunc,
                            pTimerInfo->hExpiryCbHndl,
                            pTimerInfo->uIntervalMsec,
                            pTimerInfo->bPeriodic);
        }
    }
}
예제 #3
0
/** 
 * \fn     TxMgmtQ_FlushLinkQueues
 * \brief  Flush management queues the specific link
 * 
 * * \note   
 * \param  hTxMgmtQ   - The module's object                                          
 * \param  uHlid - link id                                          
 * \return void 
 * \sa     
 */ 
void TxMgmtQ_FlushLinkQueues(TI_HANDLE hTxMgmtQ, TI_UINT32 uHlid)
{
    TTxMgmtQ   *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ;
    TTxCtrlBlk *pPktCtrlBlk;
    TI_UINT32  uQueId;
    TMgmtLinkQ *pLinkQ;

    pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */

            /* Dequeue and free all queued packets */
    for (uQueId = 0 ; uQueId < NUM_OF_MGMT_QUEUES ; uQueId++)
    {
        while (1)
        {
            context_EnterCriticalSection (pTxMgmtQ->hContext);
            pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pLinkQ->aQueues[uQueId]);
            context_LeaveCriticalSection (pTxMgmtQ->hContext);
            if (pPktCtrlBlk == NULL) 
            {
                break;
            }
            txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
        }
    }
}
예제 #4
0
/**
 * \fn     tmr_UpdateDriverState
 * \brief  Update driver state
 *
 * Under critical section, update driver state (operational or not),
 *   and if opertional, clear init queue.
 * Leave critical section and if operational state, request schedule for handling
 *   timer events in driver context (if any).
 *
 * \note
 * \param  hTimerModule - The timer module object
 * \param  bOperState   - TRUE if driver state is now operational, FALSE if not.
 * \return void
 * \sa
 */
void tmr_UpdateDriverState (TI_HANDLE hTimerModule, TI_BOOL bOperState)
{
    TTimerModule *pTimerModule = (TTimerModule *)hTimerModule;

    if (bOperState == pTimerModule->bOperState)
    {
        return;
    }

    /* Enter critical section */
    context_EnterCriticalSection (pTimerModule->hContext);

    /* Save new state (TRUE means operational). */
    pTimerModule->bOperState = bOperState;

    /* If new state is operational */
    if (bOperState)
    {
        /* Increment the TWD initializations counter (for detecting recovery events). */
        pTimerModule->uTwdInitCount++;

        /* Empty the init queue (obsolete). */
        while (que_Dequeue (pTimerModule->hInitQueue) != NULL) {}
    }

    /* Leave critical section */
    context_LeaveCriticalSection (pTimerModule->hContext);

    /* If new state is operational, request switch to driver context for handling timer events */
    if (bOperState)
    {
        context_RequestSchedule (pTimerModule->hContext, pTimerModule->uContextId);
    }
}
예제 #5
0
/**
 * \fn     txnQ_ClearQueues
 * \brief  Clear the function queues
 *
 * Clear the specified function queues and call its CB for each Txn with status=RECOVERY.
 *
 * \note   Called in critical section.
 * \param  hTxnQ            - The module's object
 * \param  uFuncId          - The calling functional driver
 * \return void
 * \sa
 */
void txnQ_ClearQueues (TI_HANDLE hTxnQ, TI_UINT32 uFuncId)
{
	TTxnQObj        *pTxnQ = (TTxnQObj*)hTxnQ;
	TTxnStruct      *pTxn;
	TI_UINT32        uPrio;

	context_EnterCriticalSection (pTxnQ->hContext);

	pTxnQ->aFuncInfo[uFuncId].pSingleStep = NULL;

	/* For all function priorities */
	for (uPrio = 0; uPrio < pTxnQ->aFuncInfo[uFuncId].uNumPrios; uPrio++) {
		do {
			/* Dequeue Txn from current priority queue */
			pTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFuncId][uPrio]);

			/*
			 * Drop on Restart
			 * do not call fTxnQueueDoneCb (hCbHandle, pTxn) callback
			 */
		} while (pTxn != NULL);
	}

	/* Clear state - for restart (doesn't call txnQ_Open) */
	pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RUNNING;

	context_LeaveCriticalSection (pTxnQ->hContext);
}
예제 #6
0
/** 
 * \fn     twIf_ClearTxnDoneQueue
 * \brief  Clean the DoneQueue
 * 
 * Clear the specified done queue - don't call the callbacks.
 *  
 * \note   
 * \param  hTwIf - The module's object
 * \return void
 * \sa     
 */
static void twIf_ClearTxnDoneQueue(TI_HANDLE hTwIf)
{
	TTwIfObj *pTwIf = (TTwIfObj *) hTwIf;
	TTxnStruct *pTxn;

	/* Loop while there are completed transactions to handle */
	while (1) {
		/* In critical section, dequeue completed transaction from the TxnDoneQ. */
		context_EnterCriticalSection(pTwIf->hContext);
		pTxn = (TTxnStruct *) que_Dequeue(pTwIf->hTxnDoneQueue);
		context_LeaveCriticalSection(pTwIf->hContext);

		/* If no more transactions to handle, exit */
		if (pTxn != NULL) {
			/* Decrement pending Txn counter */
			if (pTwIf->uPendingTxnCount > 0) {	/* in case of callback on recovery after restart */
				pTwIf->uPendingTxnCount--;
			}

			/* 
			 * Drop on Recovery 
			 * do not call pTxn->fTxnDoneCb (pTxn->hCbHandle, pTxn) callback 
			 */
		}

		if (pTxn == NULL) {
			return;
		}
	}
}
예제 #7
0
/** 
 * \fn     txDataQ_FlushLinkQueues
 * \brief  Flush all queues of the specific link
 * 
 * Free all pending packets in link queue
 *
 * \note   
 * \param  hTxDataQ - The object                                          
 * \param  uHlid - Link ID
 * \return void
 * \sa
 */ 
void txDataQ_FlushLinkQueues (TI_HANDLE hTxDataQ, TI_UINT32 uHlid)
{
    TTxDataQ   *pTxDataQ = (TTxDataQ *)hTxDataQ;
    TTxCtrlBlk *pPktCtrlBlk;
    TI_UINT32  uQueId;
    TDataLinkQ *pLinkQ;

    pLinkQ = &pTxDataQ->aDataLinkQ[uHlid]; /* Link queues */

    /* Dequeue and free all queued packets */
    for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++)
    {
        while (1)
        {
            context_EnterCriticalSection (pTxDataQ->hContext);
            pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pLinkQ->aQueues[uQueId]);
            context_LeaveCriticalSection (pTxDataQ->hContext);
            if (pPktCtrlBlk == NULL) 
            {
                break;
            }
            txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
        }
    }
}
예제 #8
0
void tmr_ClearOperQueue (TI_HANDLE hTimerModule)
{
	TTimerModule *pTimerModule = (TTimerModule *)hTimerModule;

	context_EnterCriticalSection (pTimerModule->hContext);
	while (que_Dequeue (pTimerModule->hOperQueue) != NULL) {}
	context_LeaveCriticalSection (pTimerModule->hContext);
}
예제 #9
0
/** 
 * \fn     cmdHndlr_HandleCommands 
 * \brief  Handle queued commands
 * 
 * While there are queued commands, dequeue a command and call the 
 *     commands interpreter (OID or WEXT selected at compile time).
 * If the command processing is not completed in this context (pending), we exit and 
 *     this function is called again upon commnad completion, so it can continue processing 
 *     further queued commands (if any).
 * 
 * \note    
 * \param  hCmdHndlr - The module object
 * \return void
 * \sa     cmdHndlr_InsertCommand, cmdHndlr_Complete
 */
void cmdHndlr_HandleCommands(TI_HANDLE hCmdHndlr)
{
	TCmdHndlrObj *pCmdHndlr = (TCmdHndlrObj *) hCmdHndlr;

	while (1) {
		/* Enter critical section to protect queue access */
		context_EnterCriticalSection(pCmdHndlr->hContext);

		/* Dequeue a command */
		pCmdHndlr->pCurrCmd =
		    (TConfigCommand *) que_Dequeue(pCmdHndlr->hCmdQueue);

		/* If we have got a command */
		if (pCmdHndlr->pCurrCmd) {
			/* Leave critical section */
			context_LeaveCriticalSection(pCmdHndlr->hContext);

			/* Convert to driver structure and execute command */
			pCmdHndlr->pCurrCmd->eCmdStatus =
			    cmdInterpret_convertAndExecute(pCmdHndlr->
							   hCmdInterpret,
							   pCmdHndlr->pCurrCmd);

			/* 
			 *  If command not completed in this context (Async), return.
			 *    (we'll be called back upon command completion) 
			 */
			if (COMMAND_PENDING == pCmdHndlr->pCurrCmd->eCmdStatus) {
				return;
			}

			/* Command was completed so free the wait signal and continue to next command */
			wlanDrvIf_CommandDone(pCmdHndlr->hOs,
					      pCmdHndlr->pCurrCmd->
					      pSignalObject,
					      pCmdHndlr->pCurrCmd->
					      CmdRespBuffer);

			pCmdHndlr->pCurrCmd = NULL;

		}

		/* Else, we don't have commands to handle */
		else {
			/* Indicate that we are not handling commands (before leaving critical section!) */
			pCmdHndlr->bProcessingCmds = TI_FALSE;

			/* Leave critical section */
			context_LeaveCriticalSection(pCmdHndlr->hContext);

			/* Exit (no more work) */
			return;
		}
	}
}
예제 #10
0
/** 
 * \fn     cmdHndlr_ClearQueue
 * \brief  Clear commands queue
 * 
 * Dequeue and free all queued commands.
 * 
 * \note   
 * \param  hCmdHndlr - The object                                          
 * \return void 
 * \sa     
 */ 
void cmdHndlr_ClearQueue (TI_HANDLE hCmdHndlr)
{
    TCmdHndlrObj    *pCmdHndlr = (TCmdHndlrObj *)hCmdHndlr;
    TConfigCommand  *pCurrCmd;

    /* Dequeue and free all queued commands */
    do {
        context_EnterCriticalSection (pCmdHndlr->hContext);
        pCurrCmd = (TConfigCommand *)que_Dequeue(pCmdHndlr->hCmdQueue);
        context_LeaveCriticalSection (pCmdHndlr->hContext);
        if (pCurrCmd != NULL) {
            /* Just release the semaphore. The command is freed subsequently. */
            os_SignalObjectSet (pCmdHndlr->hOs, pCurrCmd->pSignalObject);
        }
    } while (pCurrCmd != NULL);
}
/**
 * \fn     txDataQ_ClearQueues
 * \brief  Clear all queues
 *
 * Dequeue and free all queued packets.
 *
 * \note
 * \param  hTxDataQ - The object
 * \return void
 * \sa
 */
void txDataQ_ClearQueues (TI_HANDLE hTxDataQ)
{
	TTxDataQ   *pTxDataQ = (TTxDataQ *)hTxDataQ;
	TTxCtrlBlk *pPktCtrlBlk;
	TI_UINT32  uQueId;

	/* Dequeue and free all queued packets */
	for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++) {
		do {
			context_EnterCriticalSection (pTxDataQ->hContext);
			pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue(pTxDataQ->aQueues[uQueId]);
			context_LeaveCriticalSection (pTxDataQ->hContext);
			if (pPktCtrlBlk != NULL) {
				txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
			}
		} while (pPktCtrlBlk != NULL);
	}
}
/** 
 * \fn     tmr_UpdateDriverState 
 * \brief  Update driver state 
 * 
 * Under critical section, update driver state (operational or not),
 *   and if opertional, clear init queue.
 * Leave critical section and if operational state, request schedule for handling 
 *   timer events in driver context (if any).
 * 
 * \note    
 * \param  hTimerModule - The timer module object
 * \param  bOperState   - TRUE if driver state is now operational, FALSE if not.
 * \return void  
 * \sa     
 */ 
void tmr_UpdateDriverState (TI_HANDLE hTimerModule, TI_BOOL bOperState)
{
    TTimerModule *pTimerModule = (TTimerModule *)hTimerModule;

    if (!pTimerModule)
    {
        WLAN_OS_REPORT (("tmr_UpdateDriverState(): ERROR - NULL timer!\n"));
        return;
    }

    /* Enter critical section */
    context_EnterCriticalSection (pTimerModule->hContext);

    if (bOperState == pTimerModule->bOperState) 
    {
        context_LeaveCriticalSection (pTimerModule->hContext);
        TRACE1(pTimerModule->hReport, REPORT_SEVERITY_ERROR, "tmr_UpdateDriverState(): New bOperState (%d) is as current!\n", bOperState);
        return;
    }

    /* Save new state (TRUE means operational). */
    pTimerModule->bOperState = bOperState;

    /* If new state is operational */
    if (bOperState) 
    {
        /* Increment the TWD initializations counter (for detecting recovery events). */
        pTimerModule->uTwdInitCount++;

        /* Empty the init queue (obsolete). */
        while (que_Dequeue (pTimerModule->hInitQueue) != NULL) {}
    }

    /* Leave critical section */
    context_LeaveCriticalSection (pTimerModule->hContext);

    /* If new state is operational, request switch to driver context for handling timer events */
    if (bOperState) 
    {
        context_RequestSchedule (pTimerModule->hContext, pTimerModule->uContextId);
    }
}
예제 #13
0
/** 
 * \fn     txnQ_SelectTxn
 * \brief  Select transaction to send
 * 
 * Called from txnQ_RunScheduler() which is protected in critical section.
 * Select the next enabled transaction by priority.
 * 
 * \note   
 * \param  pTxnQ - The module's object
 * \return The selected transaction to send (NULL if none available)
 * \sa     
 */ 
static TTxnStruct *txnQ_SelectTxn (TTxnQObj *pTxnQ)
{
    TTxnStruct *pSelectedTxn;
    McpU32   uFunc;
    McpU32   uPrio;

    /* For all functions, if single-step Txn waiting, return it (sent even if function is stopped) */
    for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++)
    {
        pSelectedTxn = pTxnQ->aFuncInfo[uFunc].pSingleStep;
        if (pSelectedTxn != NULL)
        {
            pTxnQ->aFuncInfo[uFunc].pSingleStep = NULL;
            return pSelectedTxn;
        }
    }

    /* For all priorities from high to low */
    for (uPrio = 0; uPrio < TXN_MAX_PRIORITY; uPrio++)
    {
        /* For all functions */
        for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++)
        {
            /* If function running and uses this priority */
            if (pTxnQ->aFuncInfo[uFunc].eState == FUNC_STATE_RUNNING  &&
                pTxnQ->aFuncInfo[uFunc].uNumPrios > uPrio)
            {
                /* Dequeue Txn from current func and priority queue, and if not NULL return it */
                pSelectedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFunc][uPrio]);
                if (pSelectedTxn != NULL)
                {
                    return pSelectedTxn;
                }
            }
        }
    }

    /* If no transaction was selected, return NULL */
    return NULL;
}
예제 #14
0
/** 
 * \fn     txnQ_ClearQueues
 * \brief  Clear the function queues
 * 
 * Clear the specified function queues and call its CB for each Txn with status=RECOVERY.
 * 
 * \note   Called in critical section.
 * \param  pTxnQ            - The module's object
 * \param  uFuncId          - The calling functional driver
 * \param  bExternalContext - TRUE if called in external context (TxnDone)
 * \return void
 * \sa     
 */ 
static void txnQ_ClearQueues (TTxnQObj *pTxnQ, McpU32 uFuncId, McpBool bExternalContext)
{
    TTxnStruct      *pTxn;
    McpU32        uPrio;
    TTxnQueueDoneCb  fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb; /* function TxnDone CB */
    handle_t        hCbHandle       = pTxnQ->aFuncInfo[uFuncId].hCbHandle;
	McpBool loopCond = MCP_TRUE;

    /* If single step waiting in this function, call function CB with recovery indication */
    pTxn = pTxnQ->aFuncInfo[uFuncId].pSingleStep;
    if (pTxn != NULL)
    {
        TXN_PARAM_SET_STATUS(pTxn, TXN_STATUS_RECOVERY);
        fTxnQueueDoneCb (hCbHandle, pTxn, bExternalContext);
    }

    /* For all function priorities */
    for (uPrio = 0; uPrio < pTxnQ->aFuncInfo[uFuncId].uNumPrios; uPrio++)
    {
        while (loopCond) 
        {
            /* Dequeue Txn from current priority queue */
            pTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFuncId][uPrio]);

            /* If NULL Txn (queue empty), exit while loop */
            if (pTxn == NULL)
            {
                break;
            }

            /* Call function CB with recovery indication in the Txn */
            TXN_PARAM_SET_STATUS(pTxn, TXN_STATUS_RECOVERY);
            fTxnQueueDoneCb (hCbHandle, pTxn, bExternalContext);
        }
    }
}
예제 #15
0
/** 
 * \fn     txnQ_RunScheduler
 * \brief  Send queued transactions
 * 
 * Issue transactions as long as they are available and the bus is not occupied.
 * Call CBs of completed transactions, except conpletion of pCurrTxn (covered by the return value).
 * Note that this function can't be preempted, since it is always called in critical section 
 * See txnQ_Transact(), txnQ_SendCtrlByte(), txnQ_Run() and txnQ_TxnDoneCb().
 * 
 * \note   
 * \param  pTxnQ            - The module's object
 * \param  pCurrTxn         - The transaction inserted in the current context (NULL if none)
 * \param  bExternalContext - TRUE if called in external context (TxnDone)
 * \return COMPLETE if pCurrTxn completed in this context, PENDING if not, ERROR if failed
 * \sa     
 */ 
static ETxnStatus txnQ_RunScheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn, McpBool bExternalContext)
{
    /* Use as return value the status of the input transaction (PENDING unless sent and completed here) */
    ETxnStatus eInputTxnStatus = TXN_STATUS_PENDING; 
	McpBool loopCond = MCP_TRUE;

    /* if a previous transaction is in progress, return PENDING */
    if (pTxnQ->pCurrTxn)
    {
        return TXN_STATUS_PENDING;
    }

    /* Loop while transactions are available and can be sent to bus driver */
    while (loopCond)
    {
        TTxnStruct   *pSelectedTxn;
        ETxnStatus    eStatus;

#ifdef TRAN_DBG
#define TXN_MAX_LOOP_ITERATES 	100
		int			  loopIterates = 0;

		if (loopIterates++ >= TXN_MAX_LOOP_ITERATES)
		{
			MCPF_REPORT_WARNING (pTxnQ->hMcpf, QUEUE_MODULE_LOG, 
								 ("txnQ_RunScheduler loop reached max iterates=%d\n", loopIterates));
		}
#endif

        /* Get next enabled transaction by priority. If none, exit loop. */
        pSelectedTxn = txnQ_SelectTxn (pTxnQ);
        if (pSelectedTxn == NULL)
        {
            break;
        }

        /* Send selected transaction to bus driver */
        eStatus = busDrv_Transact (pTxnQ->hBusDrv, pSelectedTxn);

        /* If we've just sent the input transaction, use the status as the return value */
        if (pSelectedTxn == pInputTxn)
        {
            eInputTxnStatus = eStatus;
        }

        /* If transaction completed */
        if (eStatus == TXN_STATUS_COMPLETE)
        {
            /* If it's not the input transaction, enqueue it in TxnDone queue */
            if (pSelectedTxn != pInputTxn)
            {
                que_Enqueue (pTxnQ->hTxnDoneQueue, (handle_t)pSelectedTxn);
            }
        }

        /* If pending or error */
        else 
        {
            /* If transaction pending, save it to indicate that the bus driver is busy */
            if (eStatus == TXN_STATUS_PENDING)
            {
                pTxnQ->pCurrTxn = pSelectedTxn;
            }

            /* Exit loop! */
            break;
        }
    }

    /* Dequeue completed transactions and call their functional driver CB */
    /* Note that it's the functional driver CB and not the specific CB in the Txn! */
    while (loopCond)
    {
        TTxnStruct      *pCompletedTxn;
        McpU32        uFuncId;
        TTxnQueueDoneCb  fTxnQueueDoneCb;
        handle_t        hCbHandle;

        pCompletedTxn   = (TTxnStruct *) que_Dequeue (pTxnQ->hTxnDoneQueue);
        if (pCompletedTxn == NULL)
        {
            /* Return the status of the input transaction (PENDING unless sent and completed here) */
            return eInputTxnStatus;
        }

        uFuncId         = TXN_PARAM_GET_FUNC_ID(pCompletedTxn);
        fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb;
        hCbHandle       = pTxnQ->aFuncInfo[uFuncId].hCbHandle;

        fTxnQueueDoneCb (hCbHandle, pCompletedTxn, bExternalContext);
    }

	return TXN_STATUS_PENDING;
}
/**
 * \fn     txDataQ_RunScheduler
 * \brief  The module's Tx scheduler
 *
 * This function is the Data-Queue scheduler.
 * It selects a packet to transmit from the tx queues and sends it to the TxCtrl.
 * The queues are selected in a round-robin order.
 * The function is called by one of:
 *     txDataQ_Run()
 *     txDataQ_UpdateBusyMap()
 *     txDataQ_WakeAll()
 *
 * \note
 * \param  hTxDataQ - The object
 * \return void
 * \sa
 */
static void txDataQ_RunScheduler (TI_HANDLE hTxDataQ)
{
	TTxDataQ   *pTxDataQ = (TTxDataQ *)hTxDataQ;
	TI_UINT32  uIdleIterationsCount = 0;  /* Count iterations without packet transmission (for exit criteria) */
	TI_UINT32  uQueId = pTxDataQ->uLastQueId;  /* The last iteration queue */
	EStatusXmit eStatus;  /* The return status of the txCtrl_xmitData function */
	TTxCtrlBlk *pPktCtrlBlk; /* Pointer to the packet to be dequeued and sent */

	while (1) {
		/* If the Data port is closed or the scheduler couldn't send packets from
		     all queues, indicate end of current packets burst and exit */
		if ( !pTxDataQ->bDataPortEnable  ||  (uIdleIterationsCount >= pTxDataQ->uNumQueues) ) {
			TWD_txXfer_EndOfBurst (pTxDataQ->hTWD);
			return;
		}

		/* Selecting the next queue */
		uQueId++;
		if (uQueId == pTxDataQ->uNumQueues) {
			uQueId = 0;
		}
		pTxDataQ->uLastQueId = uQueId;

		/* Increment the idle iterations counter */
		uIdleIterationsCount++;

		/* If the queue is busy (AC is full), continue to next queue. */
		if (pTxDataQ->aQueueBusy[uQueId]) {
			continue;
		}

		/* Dequeue a packet in a critical section */
		context_EnterCriticalSection (pTxDataQ->hContext);
		pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pTxDataQ->aQueues[uQueId]);
		context_LeaveCriticalSection (pTxDataQ->hContext);

		/* If the queue was empty, continue to the next queue */
		if (pPktCtrlBlk == NULL) {
			if ((pTxDataQ->bStopNetStackTx) && pTxDataQ->aNetStackQueueStopped[uQueId]) {
				pTxDataQ->aNetStackQueueStopped[uQueId] = TI_FALSE;
				/*Resume the TX process as our date queues are empty*/
				wlanDrvIf_ResumeTx (pTxDataQ->hOs);
			}

			continue;
		}

#ifdef TI_DBG
		pTxDataQ->aQueueCounters[uQueId].uDequeuePacket++;
#endif /* TI_DBG */

		/* Send the packet */
		eStatus = txCtrl_XmitData (pTxDataQ->hTxCtrl, pPktCtrlBlk);

		/*
		 * If the return status is busy it means that the packet was not sent
		 *   so we need to requeue it for future try.
		 */
		if (eStatus == STATUS_XMIT_BUSY) {
			TI_STATUS eQueStatus;

			/* Requeue the packet in a critical section */
			context_EnterCriticalSection (pTxDataQ->hContext);
			eQueStatus = que_Requeue (pTxDataQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);
			if (eQueStatus != TI_OK) {
				/* If the packet can't be queued drop it */
				/* Note: may happen only if this thread was preempted between the
				   dequeue and requeue and new packets were inserted into this quque */
				txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
#ifdef TI_DBG
				pTxDataQ->aQueueCounters[uQueId].uDroppedPacket++;
#endif /* TI_DBG */
			}
			context_LeaveCriticalSection (pTxDataQ->hContext);

#ifdef TI_DBG
			pTxDataQ->aQueueCounters[uQueId].uRequeuePacket++;
#endif /* TI_DBG */

			continue;
		}

		/* If we reach this point, a packet was sent successfully so reset the idle iterations counter. */
		uIdleIterationsCount = 0;

#ifdef TI_DBG
		pTxDataQ->aQueueCounters[uQueId].uXmittedPacket++;
#endif /* TI_DBG */

	} /* End of while */

	/* Unreachable code */
}
예제 #17
0
/** 
 * \fn     twIf_HandleTxnDone
 * \brief  Completed transactions handler
 * 
 * The completed transactions handler, called upon TxnDone event, either from the context engine
 *     or directly from twIf_TxnDoneCb() if we are already in the WLAN driver's context.
 * Dequeue all completed transactions in critical section, and call their callbacks if available.
 * If awake is not required and no pending transactions in TxnQ, issue Sleep event to SM.
 *  
 * \note   
 * \param  hTwIf - The module's object
 * \return void
 * \sa     
 */
static void twIf_HandleTxnDone(TI_HANDLE hTwIf)
{
	TTwIfObj *pTwIf = (TTwIfObj *) hTwIf;
	TTxnStruct *pTxn;

	/* In case of recovery, call the recovery callback and exit */
	if (pTwIf->bTxnDoneInRecovery) {
		TRACE0(pTwIf->hReport, REPORT_SEVERITY_INFORMATION,
		       "twIf_HandleTxnDone: call RecoveryCb\n");
		pTwIf->bTxnDoneInRecovery = TI_FALSE;
		if (pTwIf->bPendRestartTimerRunning) {
			tmr_StopTimer(pTwIf->hPendRestartTimer);
			pTwIf->bPendRestartTimerRunning = TI_FALSE;
		}
		pTwIf->fRecoveryCb(pTwIf->hRecoveryCb);
		return;
	}

	/* Loop while there are completed transactions to handle */
	while (1) {
		/* In critical section, dequeue completed transaction from the TxnDoneQ. */
		context_EnterCriticalSection(pTwIf->hContext);
		pTxn = (TTxnStruct *) que_Dequeue(pTwIf->hTxnDoneQueue);
		context_LeaveCriticalSection(pTwIf->hContext);

		/* If no more transactions to handle, exit */
		if (pTxn != NULL) {
			context_EnterCriticalSection(pTwIf->hContext);
			/* Decrement pending Txn counter */
			if (pTwIf->uPendingTxnCount > 0) {	/* in case of callback on recovery after restart */
				pTwIf->uPendingTxnCount--;
			}
			context_LeaveCriticalSection(pTwIf->hContext);

			TRACE4(pTwIf->hReport, REPORT_SEVERITY_INFORMATION,
			       "twIf_HandleTxnDone: Completed-Txn: Params=0x%x, HwAddr=0x%x, Len0=%d, fTxnDoneCb=0x%x\n",
			       pTxn->uTxnParams, pTxn->uHwAddr, pTxn->aLen[0],
			       pTxn->fTxnDoneCb);

			/* If Txn failed and error CB available, call it to initiate recovery */
			if (TXN_PARAM_GET_STATUS(pTxn) ==
			    TXN_PARAM_STATUS_ERROR) {
				TRACE6(pTwIf->hReport, REPORT_SEVERITY_ERROR,
				       "twIf_HandleTxnDone: Txn failed!!  Params=0x%x, HwAddr=0x%x, Len0=%d, Len1=%d, Len2=%d, Len3=%d\n",
				       pTxn->uTxnParams, pTxn->uHwAddr,
				       pTxn->aLen[0], pTxn->aLen[1],
				       pTxn->aLen[2], pTxn->aLen[3]);

				if (pTwIf->fErrCb) {
					pTwIf->fErrCb(pTwIf->hErrCb,
						      BUS_FAILURE);
				}
				/* in error do not continue */
				return;
			}

			/* If Txn specific CB available, call it (may free Txn resources and issue new Txns) */
			if (pTxn->fTxnDoneCb != NULL) {
				((TTxnDoneCb) (pTxn->fTxnDoneCb)) (pTxn->
								   hCbHandle,
								   pTxn);
			}
		}

		/*If uPendingTxnCount == 0 and awake not required, issue Sleep event to SM */
		if ((pTwIf->uAwakeReqCount == 0)
		    && (pTwIf->uPendingTxnCount == 0)) {
			twIf_HandleSmEvent(pTwIf, SM_EVENT_SLEEP);
		}

		if (pTxn == NULL) {
			return;
		}
	}
}
예제 #18
0
/** 
 * \fn     runScheduler
 * \brief  The scheduler processing (static function)
 * 
 * Loops over the mgmt-queues (high priority first) and if queue enabled and
 *   has packets, dequeue a packet and send it to the TxCtrl.
*				Exit if the port level is disabled or if couldn't send anything from both queues.
 * 
 * \note   Protect the queues access against preemption from external context (EAPOL).
 * \param  pTxMgmtQ - The module's object                                          
 * \return void 
 * \sa     
 */ 
static void runScheduler (TTxMgmtQ *pTxMgmtQ)
{
	TI_STATUS  eStatus;
    TTxCtrlBlk *pPktCtrlBlk;
	TI_UINT32  uQueId = 0; /* start from highest priority queue */

	while(1)
	{
		/* If the Mgmt port is closed exit. */
		if ( !pTxMgmtQ->bMgmtPortEnable )
		{
			return;
		}

		/* Check that the current queue is not busy and is enabled by the state-machine. */
		if ( !pTxMgmtQ->aQueueBusy[uQueId]  &&  pTxMgmtQ->aQueueEnabledBySM[uQueId])
		{
            /* Dequeue a packet in a critical section */
            context_EnterCriticalSection (pTxMgmtQ->hContext);
            pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pTxMgmtQ->aQueues[uQueId]);
            context_LeaveCriticalSection (pTxMgmtQ->hContext);

			if (pPktCtrlBlk)
			{
				pTxMgmtQ->tDbgCounters.aDequeuePackets[uQueId]++;

				/* Send the packet */
				eStatus = txCtrl_XmitMgmt (pTxMgmtQ->hTxCtrl, pPktCtrlBlk);

				/* In case the return status is busy it means that the packet wasn't handled
					 so we need to requeue the packet for future try. */
				if(eStatus == STATUS_XMIT_BUSY)
				{
                    /* Requeue the packet in a critical section */
                    context_EnterCriticalSection (pTxMgmtQ->hContext);
                    que_Requeue (pTxMgmtQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);
                    context_LeaveCriticalSection (pTxMgmtQ->hContext);

                    pTxMgmtQ->tDbgCounters.aRequeuePackets[uQueId]++;
				}

				/* The packet was handled by the lower Tx layers. */
				else
				{
					pTxMgmtQ->tDbgCounters.aXmittedPackets[uQueId]++;

					/* Successful delivery so start next tx from the high priority queue (mgmt),
					 *	 giving it strict priority over the lower queue. 
					 */
					uQueId = 0;
					continue;
				}
			}
		}


		/* If we got here we couldn't deliver a packet from current queue, so progress to lower 
		 *	 priority queue and if already in lowest queue exit. 
		 */
		uQueId++;
		if (uQueId < NUM_OF_MGMT_QUEUES)
        {
			continue;	/* Try sending from next queue (i.e. the EAPOL queue). */
        }
		else
		{
            /* We couldn't send from both queues so indicate end of packets burst and exit. */
            TWD_txXfer_EndOfBurst (pTxMgmtQ->hTWD);
			return;		
		}

	} /* End of while */

	/* Unreachable code */
}
예제 #19
0
파일: TxnQueue.c 프로젝트: aleho/ti_wilink
/** 
 * \fn     txnQ_Scheduler
 * \brief  Send queued transactions
 * 
 * Issue transactions as long as they are available and the bus is not occupied.
 * Call CBs of completed transactions, except completion of pInputTxn (covered by the return value).
 * Note that this function is called from either internal or external (TxnDone) context.
 * However, the txnQ_RunScheduler which calls it, prevents scheduler reentry.
 * 
 * \note   
 * \param  pTxnQ     - The module's object
 * \param  pInputTxn - The transaction inserted in the current context (NULL if none)
 * \return COMPLETE if pInputTxn completed in this context, PENDING if not, ERROR if failed
 * \sa     txnQ_RunScheduler
 */ 
static ETxnStatus txnQ_Scheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn)
{
    ETxnStatus eInputTxnStatus;  

    /* Use as return value the status of the input transaction (PENDING unless sent and completed here) */
    eInputTxnStatus = TXN_STATUS_PENDING;  

    /* if a previous transaction is in progress, return PENDING */
    if (pTxnQ->pCurrTxn)
    {
        TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): pCurrTxn isn't null (0x%x) so exit\n", pTxnQ->pCurrTxn);
        return TXN_STATUS_PENDING;
    }

    /* Loop while transactions are available and can be sent to bus driver */
    while (1)
    {
        TTxnStruct   *pSelectedTxn;
        ETxnStatus    eStatus;

        /* Get next enabled transaction by priority. If none, exit loop. */
        context_EnterCriticalSection (pTxnQ->hContext);
        pSelectedTxn = txnQ_SelectTxn (pTxnQ);
        context_LeaveCriticalSection (pTxnQ->hContext);
        if (pSelectedTxn == NULL)
        {
            break;
        }

        /* Save transaction in case it will be async (to indicate that the bus driver is busy) */
        pTxnQ->pCurrTxn = pSelectedTxn;

        /* Send selected transaction to bus driver */
        eStatus = busDrv_Transact (pTxnQ->hBusDrv, pSelectedTxn);

        /* If we've just sent the input transaction, use the status as the return value */
        if (pSelectedTxn == pInputTxn)
        {
            eInputTxnStatus = eStatus;
        }

        TRACE3(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Txn 0x%x sent, status = %d, eInputTxnStatus = %d\n", pSelectedTxn, eStatus, eInputTxnStatus);

        /* If transaction completed */
        if (eStatus != TXN_STATUS_PENDING)
        {
            pTxnQ->pCurrTxn = NULL;

            /* If it's not the input transaction, enqueue it in TxnDone queue */
            if (pSelectedTxn != pInputTxn)
            {
                TI_STATUS eStatus;

                context_EnterCriticalSection (pTxnQ->hContext);
                eStatus = que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pSelectedTxn);
                if (eStatus != TI_OK)
                {
                    TRACE3(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_Scheduler(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pSelectedTxn, pSelectedTxn->uHwAddr, pSelectedTxn->aLen[0]);
                }
                context_LeaveCriticalSection (pTxnQ->hContext);
            }
        }

        /* If pending Exit loop! */
        else 
        {
            break;
        }
    }

    /* Dequeue completed transactions and call their functional driver CB */
    /* Note that it's the functional driver CB and not the specific CB in the Txn! */
    while (1)
    {
        TTxnStruct      *pCompletedTxn;
        TI_UINT32        uFuncId;
        TTxnQueueDoneCb  fTxnQueueDoneCb;
        TI_HANDLE        hCbHandle;

        context_EnterCriticalSection (pTxnQ->hContext);
        pCompletedTxn   = (TTxnStruct *) que_Dequeue (pTxnQ->hTxnDoneQueue);
        context_LeaveCriticalSection (pTxnQ->hContext);
        if (pCompletedTxn == NULL)
        {
            /* Return the status of the input transaction (PENDING unless sent and completed here) */
            return eInputTxnStatus;
        }

        TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Calling TxnDone for Txn 0x%x\n", pCompletedTxn);

        uFuncId         = TXN_PARAM_GET_FUNC_ID(pCompletedTxn);
        fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb;
        hCbHandle       = pTxnQ->aFuncInfo[uFuncId].hCbHandle;

        fTxnQueueDoneCb (hCbHandle, pCompletedTxn);
    }
}
예제 #20
0
/** 
 * \fn     runScheduler
 * \brief  The scheduler processing (static function)
 * 
 * Loops over the mgmt-queues (high priority first) and if queue enabled and
 *   has packets, dequeue a packet and send it to the TxCtrl.
*				Exit if the port level is disabled or if couldn't send anything from both queues.
 * 
 * \note   Protect the queues access against preemption from external context (EAPOL).
 * \param  pTxMgmtQ - The module's object                                          
 * \return void 
 * \sa     
 */ 
static void runScheduler (TTxMgmtQ *pTxMgmtQ)
{
	TI_STATUS  eStatus;
    TTxCtrlBlk *pPktCtrlBlk;
	TI_UINT32  uQueId = 0; /* start from highest priority queue */
    TMgmtLinkQ *pLinkQ;
    TI_UINT32 uHlid = 0;
    TI_BOOL bQueueActive;
    TI_BOOL bLinkActive;


	while(1)
	{
        /* If the Mgmt port is closed or AC for mgmt is busy, exit. */
        if ( (!pTxMgmtQ->bMgmtPortEnable) || (pTxMgmtQ->aMgmtAcBusy) )
		{
			return;
		}

		pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */
		bLinkActive = ( (!pLinkQ->bBusy) && pLinkQ->bEnabled );
        bQueueActive = pLinkQ->aQenabled[uQueId];

		/* Check that the current link and current queue are not busy and are enabled */
		if ( bLinkActive && bQueueActive)
		{
            /* Dequeue a packet in a critical section */
            context_EnterCriticalSection (pTxMgmtQ->hContext);
            pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pLinkQ->aQueues[uQueId]);
            context_LeaveCriticalSection (pTxMgmtQ->hContext);

			if (pPktCtrlBlk)
			{
				pLinkQ->tDbgCounters.aDequeuePackets[uQueId]++;

				/* Send the packet */
				eStatus = txCtrl_XmitMgmt (pTxMgmtQ->hTxCtrl, pPktCtrlBlk);

              
				/* In case the return status is busy it means that the packet wasn't handled
					 so we need to requeue the packet for future try. */
				if(eStatus == STATUS_XMIT_BUSY)
				{
                    /* Requeue the packet in a critical section */
                    context_EnterCriticalSection (pTxMgmtQ->hContext);
                    que_Requeue (pLinkQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);
                    context_LeaveCriticalSection (pTxMgmtQ->hContext);

                    pLinkQ->tDbgCounters.aRequeuePackets[uQueId]++;
				}

				/* The packet was handled by the lower Tx layers. */
				else
				{
					pLinkQ->tDbgCounters.aXmittedPackets[uQueId]++;

					/* Successful delivery so start next tx from the high priority queue (mgmt),
					 *	 giving it strict priority over the lower queue. 
					 */
					uQueId = 0;
					continue;
				}
			}
		}

		/* If we got here we couldn't deliver a packet from current queue, so progress to lower 
		 *	 priority queue and if already in lowest queue exit. 
		 */
        if (bLinkActive) /* Continue to next queue only if the link is active */
        {
		uQueId++;
		if (uQueId < NUM_OF_MGMT_QUEUES)
        {
			continue;	/* Try sending from next queue (i.e. the EAPOL queue). */
        }
        }
    
        /*
         * continue to next link
         */
			uHlid++;
			if (uHlid < WLANLINKS_MAX_LINKS)
			{
			    uQueId = 0;
			    continue;
			}
			else
			{
            /* We couldn't send from both queues so indicate end of packets burst and exit. */
            TWD_txXfer_EndOfBurst (pTxMgmtQ->hTWD);
			return;		
		}

	} /* End of while */

	/* Unreachable code */
}
예제 #21
0
/**
 * \fn     txDataQ_RunScheduler
 * \brief  The module's Tx scheduler
 *
 * This function is the Data-Queue scheduler.
 * It selects a packet to transmit from the tx queues and sends it to the TxCtrl.
 * The queues are selected in a round-robin order.
 * The function is called by one of:
 *     txDataQ_Run()
 *     txDataQ_UpdateBusyMap()
 *     txDataQ_WakeAll()
 *
 * \note
 * \param  hTxDataQ - The object
 * \return void
 * \sa
 */
static void txDataQ_RunScheduler (TI_HANDLE hTxDataQ)
{
	TTxDataQ   *pTxDataQ = (TTxDataQ *)hTxDataQ;
	TI_UINT32  uIdleAcCount = 0;  /* Count AC queues iterations without packet transmission (for exit criteria) */
	TI_UINT32  uIdleLinkCount = 0;  /* Count Links iterations without packet transmission (for exit criteria) */
	TI_UINT32  uQueId = pTxDataQ->uNextQueId;  /* The last iteration queue */
	EStatusXmit eStatus;  /* The return status of the txCtrl_xmitData function */
	TTxCtrlBlk *pPktCtrlBlk; /* Pointer to the packet to be dequeued and sent */
	TI_UINT32  uHlid = pTxDataQ->uNextHlid;  /* The last iteration link */
	TDataLinkQ *pLinkQ;
	TI_BOOL bStopScheduler = TI_FALSE;

	while(!bStopScheduler) {
		bStopScheduler = TI_TRUE;
		for(uIdleLinkCount = 0; uIdleLinkCount < WLANLINKS_MAX_LINKS; uIdleLinkCount++) {
			/* If the Data port is closed, indicate end of current packets burst and exit */
			if ( !pTxDataQ->bDataPortEnable ) {
				TWD_txXfer_EndOfBurst (pTxDataQ->hTWD);
				return;
			}
			if (uHlid == WLANLINKS_MAX_LINKS) {
				uHlid = 0;
			}

			pLinkQ = &pTxDataQ->aDataLinkQ[uHlid]; /* Link queues */
			/* If the link is busy (AC is full), continue to next queue. */
			if ( (!pLinkQ->bEnabled) || (pLinkQ->bBusy)) {
				uQueId = 0;
				uHlid++;
				continue;
			}

			for(uIdleAcCount = 0; uIdleAcCount < pTxDataQ->uNumQueues; uIdleAcCount++) {
				if ( !pTxDataQ->bDataPortEnable ) {
					TWD_txXfer_EndOfBurst (pTxDataQ->hTWD);
					return;
				}

				if (uQueId == pTxDataQ->uNumQueues) {
					uQueId = 0;
				}
				if (pTxDataQ->aQueueBusy[uQueId]) {
					uQueId++;
					continue;
				}
				/* Dequeue a packet in a critical section */
				context_EnterCriticalSection (pTxDataQ->hContext);
				pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pLinkQ->aQueues[uQueId]);
				context_LeaveCriticalSection (pTxDataQ->hContext);

				/* If the queue was empty, continue to the next queue */
				if (pPktCtrlBlk == NULL) {
					if ((pTxDataQ->bStopNetStackTx) && pLinkQ->aNetStackQueueStopped[uQueId]) {
						pLinkQ->aNetStackQueueStopped[uQueId] = TI_FALSE;
						/*Resume the TX process as our date queues are empty*/
						wlanDrvIf_ResumeTx (pTxDataQ->hOs);
					}
					uQueId++;
					continue;
				}

#ifdef TI_DBG
				pLinkQ->aQueueCounters[uQueId].uDequeuePacket++;
#endif /* TI_DBG */
				/* Send the packet */
				eStatus = txCtrl_XmitData (pTxDataQ->hTxCtrl, pPktCtrlBlk);

				/*
				 * If the return status is busy it means that the packet was not sent
				 *   so we need to requeue it for future try.
				 */
				if(eStatus == STATUS_XMIT_BUSY) {
					TI_STATUS eQueStatus;

					/* Requeue the packet in a critical section */
					context_EnterCriticalSection (pTxDataQ->hContext);
					eQueStatus = que_Requeue (pLinkQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);
					if (eQueStatus != TI_OK) {
						/* If the packet can't be queued drop it */
						/* Note: may happen only if this thread was preempted between the
						   dequeue and requeue and new packets were inserted into this quque */
						txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
#ifdef TI_DBG
						pLinkQ->aQueueCounters[uQueId].uDroppedPacket++;
#endif /* TI_DBG */
					}
					context_LeaveCriticalSection (pTxDataQ->hContext);

#ifdef TI_DBG
					pLinkQ->aQueueCounters[uQueId].uRequeuePacket++;
#endif /* TI_DBG */
					uQueId++;
					continue;
				} else if( eStatus == STATUS_XMIT_SUCCESS ) {

					bStopScheduler = TI_FALSE;
					/* Save the next que should be proceed by scheduler */
					pTxDataQ->uNextQueId = uQueId + 1;
					pTxDataQ->uNextHlid = uHlid + 1;
				}
#ifdef TI_DBG
				pLinkQ->aQueueCounters[uQueId].uXmittedPacket++;
#endif /* TI_DBG */

				uQueId++;
			} /* for(uIdleAcCount = 0; uIdleAcCount < pTxDataQ->uNumQueues; uIdleAcCount++)*/
			uHlid++;

		}  /*for(uIdleLinkCount = 0; uIdleLinkCount < WLANLINKS_MAX_LINKS; uIdleLinkCount++)*/
	}  /*while(!bStopScheduler)*/
	TWD_txXfer_EndOfBurst (pTxDataQ->hTWD);

}