/**
 * \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 */
}
Example #2
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);

}