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