/** * \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); } } }
/** * \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); } } }
/** * \fn txMgmtQ_Xmit * \brief Insert non-data packet for transmission * * This function is used by the driver applications to send Tx packets other than the * regular data traffic, including the following packet types: * - Management * - EAPOL * - NULL * - IAPP * The managment packets are enqueued to the Mgmt-queue and the others to the Eapol-queue. * EAPOL packets may be inserted from the network stack context, so it requires switching * to the driver's context (after the packet is enqueued). * If the selected queue was empty before the packet insertion, the SM is called * with QUEUES_NOT_EMPTY event (in case of external context, only after the context switch). * * \note * \param hTxMgmtQ - The module's object * \param pPktCtrlBlk - Pointer to the packet CtrlBlk * \param bExternalContext - Indicates if called from non-driver context * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped. * \sa txMgmtQ_QueuesNotEmpty */ TI_STATUS txMgmtQ_Xmit (TI_HANDLE hTxMgmtQ, TTxCtrlBlk *pPktCtrlBlk, TI_BOOL bExternalContext) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; /* Always set highest TID for mgmt-queues packets. */ pPktCtrlBlk->tTxDescriptor.tid = MGMT_QUEUES_TID; /* Select queue asccording to the packet type */ uQueId = (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) ? QUEUE_TYPE_MGMT : QUEUE_TYPE_EAPOL ; /* Enter critical section to protect queue access */ context_EnterCriticalSection (pTxMgmtQ->hContext); /* Enqueue the packet in the appropriate Queue */ eStatus = que_Enqueue (pTxMgmtQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pTxMgmtQ->aQueues[uQueId]); /* Leave critical section */ context_LeaveCriticalSection (pTxMgmtQ->hContext); /* If packet enqueued successfully */ if (eStatus == TI_OK) { pTxMgmtQ->tDbgCounters.aEnqueuePackets[uQueId]++; /* If selected queue was empty before packet insertion */ if (uQueSize == 1) { /* If called from external context (EAPOL from network), request switch to the driver's context. */ if (bExternalContext) { context_RequestSchedule (pTxMgmtQ->hContext, pTxMgmtQ->uContextId); } /* If already in the driver's context, call the SM with QUEUES_NOT_EMPTY event. */ else { mgmtQueuesSM(pTxMgmtQ, SM_EVENT_QUEUES_NOT_EMPTY); } } } else { /* If the packet can't be queued so drop it */ txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); pTxMgmtQ->tDbgCounters.aDroppedPackets[uQueId]++; } return eStatus; }
/** * \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 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 */ }
TI_STATUS txDataQ_InsertPacket (TI_HANDLE hTxDataQ, TTxCtrlBlk *pPktCtrlBlk, TI_UINT8 uPacketDtag) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; TEthernetHeader *pEthHead = (TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]); TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; txCtrl_t *pTxCtrl = (txCtrl_t *)(pTxDataQ->hTxCtrl); TI_BOOL bRequestSchedule = TI_FALSE; TI_BOOL bStopNetStack = TI_FALSE; CL_TRACE_START_L3(); /* If packet is EAPOL or from the generic Ethertype, forward it to the Mgmt-Queue and exit */ if ((HTOWLANS(pEthHead->type) == ETHERTYPE_EAPOL) || (HTOWLANS(pEthHead->type) == pTxCtrl->genericEthertype)) { pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_EAPOL; return txMgmtQ_Xmit (pTxDataQ->hTxMgmtQ, pPktCtrlBlk, TI_TRUE); /* Note: The last parameter indicates that we are running in external context */ } pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_ETHER; /* Enter critical section to protect classifier data and queue access */ context_EnterCriticalSection (pTxDataQ->hContext); /* Call the Classify function to set the TID field */ if (txDataClsfr_ClassifyTxPacket (hTxDataQ, pPktCtrlBlk, uPacketDtag) != TI_OK) { #ifdef TI_DBG pTxDataQ->uClsfrMismatchCount++; TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_WARNING, "txDataQueue_xmit: No matching classifier found \n"); #endif /* TI_DBG */ } /* Enqueue the packet in the appropriate Queue */ uQueId = aTidToQueueTable[pPktCtrlBlk->tTxDescriptor.tid]; eStatus = que_Enqueue (pTxDataQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pTxDataQ->aQueues[uQueId]); /* If the current queue is not stopped */ if (pTxDataQ->aQueueBusy[uQueId] == TI_FALSE) { /* If the queue has the desired number of packets, request switch to driver context for handling them */ if (uQueSize == pTxDataQ->aTxSendPaceThresh[uQueId]) { tmr_StopTimer (pTxDataQ->hTxSendPaceTimer); bRequestSchedule = TI_TRUE; } /* If below Tx-Send pacing threshold, start timer to trigger packets handling if expired */ else if (uQueSize < pTxDataQ->aTxSendPaceThresh[uQueId]) { tmr_StartTimer (pTxDataQ->hTxSendPaceTimer, txDataQ_TxSendPaceTimeout, hTxDataQ, TX_SEND_PACE_TIMEOUT_MSEC, TI_FALSE); } } /* If allowed to stop network stack and the queue is full, indicate to stop network and to schedule Tx handling (both are executed below, outside the critical section!) */ if ((pTxDataQ->bStopNetStackTx) && (uQueSize == pTxDataQ->aQueueMaxSize[uQueId])) { pTxDataQ->aNetStackQueueStopped[uQueId] = TI_TRUE; bRequestSchedule = TI_TRUE; bStopNetStack = TI_TRUE; } /* Leave critical section */ context_LeaveCriticalSection (pTxDataQ->hContext); /* If needed, schedule Tx handling */ if (bRequestSchedule) { context_RequestSchedule (pTxDataQ->hContext, pTxDataQ->uContextId); } /* If needed, stop the network stack Tx */ if (bStopNetStack) { /* Stop the network stack from sending Tx packets as we have at least one date queue full. Note that in some of the OS's (e.g Win Mobile) it is implemented by blocking the thread*/ wlanDrvIf_StopTx (pTxDataQ->hOs); } if (eStatus != TI_OK) { /* If the packet can't be queued drop it */ txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); #ifdef TI_DBG pTxDataQ->aQueueCounters[uQueId].uDroppedPacket++; #endif /* TI_DBG */ } else { #ifdef TI_DBG pTxDataQ->aQueueCounters[uQueId].uEnqueuePacket++; #endif /* TI_DBG */ } CL_TRACE_END_L3 ("tiwlan_drv.ko", "INHERIT", "TX", ""); return eStatus; }
/** * \fn txMgmtQ_Xmit * \brief Insert non-data packet for transmission * * This function is used by the driver applications to send Tx packets other than the * regular data traffic, including the following packet types: * - Management * - EAPOL * - NULL * - IAPP * The managment packets are enqueued to the Mgmt-queue and the others to the Eapol-queue. * EAPOL packets may be inserted from the network stack context, so it requires switching * to the driver's context (after the packet is enqueued). * If the selected queue was empty before the packet insertion, the SM is called * with QUEUES_NOT_EMPTY event (in case of external context, only after the context switch). * * \note * \param hTxMgmtQ - The module's object * \param pPktCtrlBlk - Pointer to the packet CtrlBlk * \param bExternalContext - Indicates if called from non-driver context * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped. * \sa txMgmtQ_QueuesNotEmpty */ TI_STATUS txMgmtQ_Xmit (TI_HANDLE hTxMgmtQ, TTxCtrlBlk *pPktCtrlBlk, TI_BOOL bExternalContext) { TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; TI_UINT32 uHlid; TMgmtLinkQ *pLinkQ; /* Find link id by destination MAC address, if not found use global link id */ if (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) { /* MGMT packet, use destination MAC address from WLAN header, aBuf[0] is the WLAN header */ if ((txDataQ_LinkMacFind( pTxMgmtQ->hTxDataQ, &uHlid ,((dot11_header_t *)(pPktCtrlBlk->tTxnStruct.aBuf[0]))->address1 )) != TI_OK) { uHlid = pTxMgmtQ->uGlobalHlid; } } else { /* EAPOL packet, use destination MAC address from ETHERNET header, aBuf[0] is the ETHERNET header */ if ((txDataQ_LinkMacFind( pTxMgmtQ->hTxDataQ, &uHlid, ((TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]))->dst)) != TI_OK) { uHlid = pTxMgmtQ->uGlobalHlid; } } pPktCtrlBlk->tTxDescriptor.hlid = uHlid; pLinkQ = &pTxMgmtQ->aMgmtLinkQ[uHlid]; /* Link queues */ /* Always set highest TID for mgmt-queues packets. */ pPktCtrlBlk->tTxDescriptor.tid = MGMT_QUEUES_TID; if ((pLinkQ->bEncrypt)&& (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_EAPOL)) { SET_PKT_TYPE_ENCRYPT(pPktCtrlBlk); } /* Select queue asccording to the packet type */ uQueId = (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) ? QUEUE_TYPE_MGMT : QUEUE_TYPE_EAPOL ; /* Enter critical section to protect queue access */ context_EnterCriticalSection (pTxMgmtQ->hContext); /* Check resources per LINK and per MGMT AC (VOICE)*/ if (txDataQ_AllocCheckResources( pTxMgmtQ->hTxDataQ, pPktCtrlBlk) != TI_OK) { pLinkQ->tDbgCounters.aDroppedPackets[uQueId]++; pLinkQ->tDbgCounters.uNoResourcesCount++; /* Leave critical section */ context_LeaveCriticalSection (pTxMgmtQ->hContext); /* If the packet can't be queued drop it */ /* !!! This call should be out of the critical section */ txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); return TI_NOK; } /* Enqueue the packet in the appropriate Queue */ eStatus = que_Enqueue (pLinkQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pLinkQ->aQueues[uQueId]); /* Leave critical section */ context_LeaveCriticalSection (pTxMgmtQ->hContext); /* If packet enqueued successfully */ if (eStatus == TI_OK) { pLinkQ->tDbgCounters.aEnqueuePackets[uQueId]++; /* If selected queue was empty before packet insertion */ if (uQueSize == 1 ) if (uQueSize ) { /* If called from external context (EAPOL from network), request switch to the driver's context. */ if (bExternalContext) { /* Set bSendEvent_NotEmpty flag to use in driver context */ pLinkQ->bSendEvent_NotEmpty = TI_TRUE; context_RequestSchedule (pTxMgmtQ->hContext, pTxMgmtQ->uContextId); } /* If already in the driver's context, call the SM with QUEUES_NOT_EMPTY event. */ else { mgmtQueuesSM(pTxMgmtQ, uHlid, SM_EVENT_QUEUES_NOT_EMPTY); } } } else { /* If the packet can't be queued so drop it */ txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); pLinkQ->tDbgCounters.aDroppedPackets[uQueId]++; } return eStatus; }
TI_STATUS txDataQ_InsertPacket (TI_HANDLE hTxDataQ, TTxCtrlBlk *pPktCtrlBlk, TI_UINT8 uPacketDtag, TIntraBssBridge *pIntraBssBridgeParam) { TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; TEthernetHeader *pEthHead = (TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]); TI_STATUS eStatus; TI_UINT32 uQueId; TI_UINT32 uQueSize; txCtrl_t *pTxCtrl = (txCtrl_t *)(pTxDataQ->hTxCtrl); TI_BOOL bRequestSchedule = TI_FALSE; TI_BOOL bStopNetStack = TI_FALSE; TDataLinkQ *pLinkQ; TI_UINT32 uHlid; /* If packet is EAPOL or from the generic Ethertype, forward it to the Mgmt-Queue and exit */ if ((HTOWLANS(pEthHead->type) == ETHERTYPE_EAPOL) || (HTOWLANS(pEthHead->type) == pTxCtrl->genericEthertype)) { pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_EAPOL; return txMgmtQ_Xmit (pTxDataQ->hTxMgmtQ, pPktCtrlBlk, TI_TRUE); /* Note: The last parameter indicates that we are running in external context */ } /* Find link id by destination MAC address, if not found drop the packet */ /* use Intra Bss bridge params*/ if(!pIntraBssBridgeParam) { if (TI_UNLIKELY(MAC_MULTICAST(pEthHead->dst))) { uHlid = pTxDataQ->uBcastHlid; } else { if (txDataQ_LinkMacFind( hTxDataQ, &uHlid, pEthHead->dst) != TI_OK) { /* If the packet can't be queued drop it */ txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); pTxDataQ->uLinkNotFoundCount++; return TI_NOK; } } } else { uHlid = pIntraBssBridgeParam->uParam; } pPktCtrlBlk->tTxDescriptor.hlid = uHlid; pLinkQ = &pTxDataQ->aDataLinkQ[uHlid]; /* Link queues */ pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_ETHER; /* set encryption bit */ if (pLinkQ->bEncrypt) { SET_PKT_TYPE_ENCRYPT(pPktCtrlBlk); } /* Enter critical section to protect classifier data and queue access */ context_EnterCriticalSection (pTxDataQ->hContext); /* Call the Classify function to set the TID field */ if (txDataClsfr_ClassifyTxPacket (hTxDataQ, pPktCtrlBlk, uPacketDtag) != TI_OK) { #ifdef TI_DBG pTxDataQ->uClsfrMismatchCount++; #endif /* TI_DBG */ } uQueId = aTidToQueueTable[pPktCtrlBlk->tTxDescriptor.tid]; /* Check resources per LINK and per AC */ if (txDataQ_AllocCheckResources( hTxDataQ, pPktCtrlBlk) != TI_OK) { #ifdef TI_DBG pLinkQ->aQueueCounters[uQueId].uDroppedPacket++; pTxDataQ->uNoResourcesCount++; #endif /* TI_DBG */ /* Leave critical section */ context_LeaveCriticalSection (pTxDataQ->hContext); /* If the packet can't be queued drop it - Should be out of the critical section */ /* !!! This call should be out of the critical section */ txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); return TI_NOK; } /* Enqueue the packet in the appropriate Queue */ eStatus = que_Enqueue (pLinkQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); /* Get number of packets in current queue */ uQueSize = que_Size (pLinkQ->aQueues[uQueId]); /* If the current queue is not stopped */ if (pTxDataQ->aQueueBusy[uQueId] == TI_FALSE) { /* If the queue has the desired number of packets, request switch to driver context for handling them */ if (uQueSize == pTxDataQ->aTxSendPaceThresh[uQueId]) { tmr_StopTimer (pTxDataQ->hTxSendPaceTimer); bRequestSchedule = TI_TRUE; } /* If below Tx-Send pacing threshold, start timer to trigger packets handling if expired */ else if (uQueSize < pTxDataQ->aTxSendPaceThresh[uQueId]) { tmr_StartTimer (pTxDataQ->hTxSendPaceTimer, txDataQ_TxSendPaceTimeout, hTxDataQ, TX_SEND_PACE_TIMEOUT_MSEC, TI_FALSE); } } /* If allowed to stop network stack and the queue is full, indicate to stop network and to schedule Tx handling (both are executed below, outside the critical section!) */ if ((pTxDataQ->bStopNetStackTx) && (uQueSize == pTxDataQ->aQueueMaxSize[uQueId])) { pLinkQ->aNetStackQueueStopped[uQueId] = TI_TRUE; bRequestSchedule = TI_TRUE; bStopNetStack = TI_TRUE; } /* Leave critical section */ context_LeaveCriticalSection (pTxDataQ->hContext); /* If needed, schedule Tx handling */ if (bRequestSchedule) { context_RequestSchedule (pTxDataQ->hContext, pTxDataQ->uContextId); } /* If needed, stop the network stack Tx */ if (bStopNetStack) { /* Stop the network stack from sending Tx packets as we have at least one date queue full. Note that in some of the OS's (e.g Win Mobile) it is implemented by blocking the thread! */ wlanDrvIf_StopTx (pTxDataQ->hOs); } if (eStatus != TI_OK) { /* If the packet can't be queued drop it */ txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); #ifdef TI_DBG pLinkQ->aQueueCounters[uQueId].uDroppedPacket++; #endif /* TI_DBG */ } else { #ifdef TI_DBG pLinkQ->aQueueCounters[uQueId].uEnqueuePacket++; #endif /* TI_DBG */ } return eStatus; }
/** * \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); }
TI_STATUS mlmeBuilder_sendFrame(TI_HANDLE hMlme, dot11MgmtSubType_e type, TI_UINT8 *pDataBuff, TI_UINT32 dataLen, TI_UINT8 setWepOpt) { mlme_t *pHandle = (mlme_t*)hMlme; TI_STATUS status; TTxCtrlBlk *pPktCtrlBlk; TI_UINT8 *pPktBuffer; TMacAddr daBssid, saBssid; dot11_mgmtHeader_t *pDot11Header; /* Allocate a TxCtrlBlk and data buffer (large enough for the max management packet) */ pPktCtrlBlk = TWD_txCtrlBlk_Alloc (pHandle->hTWD); if (pPktCtrlBlk == NULL) return TI_NOK; pPktBuffer = txCtrl_AllocPacketBuffer (pHandle->hTxCtrl, pPktCtrlBlk, MAX_MANAGEMENT_FRAME_BODY_LEN + WLAN_HDR_LEN); if (pPktBuffer == NULL) { TRACE0(pHandle->hReport, REPORT_SEVERITY_ERROR , ": No memory\n"); TWD_txCtrlBlk_Free (pHandle->hTWD, pPktCtrlBlk); return TI_NOK; } pDot11Header = (dot11_mgmtHeader_t *)(pPktCtrlBlk->aPktHdr); status = mlmeBuilder_buildFrameCtrl (pHandle, type, (TI_UINT16 *)&pDot11Header->fc, setWepOpt); if (status != TI_OK) { txCtrl_FreePacket (pHandle->hTxCtrl, pPktCtrlBlk, TI_NOK); return TI_NOK; } status = ctrlData_getParamBssid(pHandle->hCtrlData, CTRL_DATA_CURRENT_BSSID_PARAM, daBssid); if (status != TI_OK) { txCtrl_FreePacket (pHandle->hTxCtrl, pPktCtrlBlk, TI_NOK); return TI_NOK; } /* copy destination mac address */ MAC_COPY (pDot11Header->DA, daBssid); status = ctrlData_getParamMacAddr(pHandle->hCtrlData, saBssid); if (status != TI_OK) { txCtrl_FreePacket (pHandle->hTxCtrl, pPktCtrlBlk, TI_NOK); return TI_NOK; } /* copy source mac address */ MAC_COPY (pDot11Header->SA, saBssid); /* copy BSSID (destination mac address) */ MAC_COPY (pDot11Header->BSSID, daBssid); if (pDataBuff != NULL) { os_memoryCopy (pHandle->hOs, pPktBuffer, pDataBuff, dataLen); } /* Update packet parameters (start-time, length, pkt-type) */ pPktCtrlBlk->tTxDescriptor.startTime = os_timeStampMs (pHandle->hOs); pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_MGMT; BUILD_TX_TWO_BUF_PKT_BDL (pPktCtrlBlk, (TI_UINT8 *)pDot11Header, WLAN_HDR_LEN, pPktBuffer, dataLen) /* Enqueue packet in the mgmt-queues and run the scheduler. */ status = txMgmtQ_Xmit (pHandle->hTxMgmtQ, pPktCtrlBlk, TI_FALSE); return status; }