/**
 * \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 */
}
Esempio n. 2
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 */
}
/** 
 * \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 */
}
Esempio n. 4
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);

}