Home | History | Annotate | Download | only in Data_link
      1 /*
      2  * txDataQueue.c
      3  *
      4  * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  *
     11  *  * Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  *  * Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *  * Neither the name Texas Instruments nor the names of its
     18  *    contributors may be used to endorse or promote products derived
     19  *    from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 
     35 /** \file   txDataQueue.c
     36  *  \brief  The Tx Data Queues module.
     37  *
     38  *  \see    txDataQueue.h
     39  */
     40 
     41 
     42 #define __FILE_ID__  FILE_ID_60
     43 #include "paramOut.h"
     44 #include "osApi.h"
     45 #include "report.h"
     46 #include "timer.h"
     47 #include "queue.h"
     48 #include "context.h"
     49 #include "Ethernet.h"
     50 #include "TWDriver.h"
     51 #include "DataCtrl_Api.h"
     52 #include "txDataQueue.h"
     53 #include "txCtrl.h"
     54 #include "DrvMainModules.h"
     55 #include "bmtrace_api.h"
     56 
     57 
     58 /* Internal Functions prototypes */
     59 static void txDataQ_RunScheduler (TI_HANDLE hTxDataQ);
     60 static void txDataQ_UpdateQueuesBusyState (TTxDataQ *pTxDataQ, TI_UINT32 uTidBitMap);
     61 static void txDataQ_TxSendPaceTimeout (TI_HANDLE hTxDataQ, TI_BOOL bTwdInitOccured);
     62 extern void wlanDrvIf_StopTx (TI_HANDLE hOs);
     63 extern void wlanDrvIf_ResumeTx (TI_HANDLE hOs);
     64 
     65 
     66 
     67 /***************************************************************************
     68 *                      PUBLIC  FUNCTIONS  IMPLEMENTATION				   *
     69 ****************************************************************************/
     70 
     71 
     72 /**
     73  * \fn     txDataQ_Create
     74  * \brief  Create the module and its queues
     75  *
     76  * Create the Tx Data module and its queues.
     77  *
     78  * \note
     79  * \param  hOs - Handle to the Os Abstraction Layer
     80  * \return Handle to the allocated Tx Data Queue module (NULL if failed)
     81  * \sa
     82  */
     83 TI_HANDLE txDataQ_Create(TI_HANDLE hOs)
     84 {
     85     TTxDataQ *pTxDataQ;
     86 
     87     /* allocate TxDataQueue module */
     88     pTxDataQ = os_memoryAlloc (hOs, (sizeof(TTxDataQ)));
     89 
     90     if (!pTxDataQ)
     91 	{
     92         WLAN_OS_REPORT(("Error allocating the TxDataQueue Module\n"));
     93 		return NULL;
     94 	}
     95 
     96     /* Reset TxDataQueue module */
     97     os_memoryZero (hOs, pTxDataQ, (sizeof(TTxDataQ)));
     98 
     99     return (TI_HANDLE)pTxDataQ;
    100 }
    101 
    102 
    103 /**
    104  * \fn     txDataQ_Init
    105  * \brief  Save required modules handles
    106  *
    107  * Save other modules handles.
    108  *
    109  * \note
    110  * \param  pStadHandles  - The driver modules handles
    111  * \return void
    112  * \sa
    113  */
    114 void txDataQ_Init (TStadHandlesList *pStadHandles)
    115 {
    116     TTxDataQ  *pTxDataQ = (TTxDataQ *)(pStadHandles->hTxDataQ);
    117     TI_UINT32  uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode);
    118     TI_UINT8   uQueId;
    119 
    120     /* save modules handles */
    121     pTxDataQ->hContext	= pStadHandles->hContext;
    122     pTxDataQ->hTxCtrl	= pStadHandles->hTxCtrl;
    123     pTxDataQ->hOs		= pStadHandles->hOs;
    124     pTxDataQ->hReport	= pStadHandles->hReport;
    125     pTxDataQ->hTxMgmtQ	= pStadHandles->hTxMgmtQ;
    126     pTxDataQ->hTWD	    = pStadHandles->hTWD;
    127 
    128     /* Configures the Port Default status to Close */
    129 	pTxDataQ->bDataPortEnable = TI_FALSE;
    130 
    131 	/* Configures the LastQueId to zero => scheduler will strart from Queue 1*/
    132 	pTxDataQ->uLastQueId = 0;
    133 
    134 	/* init the number of the Data queue to be used */
    135 	pTxDataQ->uNumQueues = MAX_NUM_OF_AC;
    136 
    137 	/* init the max size of the Data queues */
    138 	pTxDataQ->aQueueMaxSize[QOS_AC_BE] = DATA_QUEUE_DEPTH_BE;
    139 	pTxDataQ->aQueueMaxSize[QOS_AC_BK] = DATA_QUEUE_DEPTH_BK;
    140 	pTxDataQ->aQueueMaxSize[QOS_AC_VI] = DATA_QUEUE_DEPTH_VI;
    141 	pTxDataQ->aQueueMaxSize[QOS_AC_VO] = DATA_QUEUE_DEPTH_VO;
    142 
    143     /* Create the tx data queues */
    144 	for (uQueId = 0; uQueId < pTxDataQ->uNumQueues; uQueId++)
    145     {
    146         pTxDataQ->aQueues[uQueId] = que_Create (pTxDataQ->hOs,
    147                                                 pTxDataQ->hReport,
    148                                                 pTxDataQ->aQueueMaxSize[uQueId],
    149                                                 uNodeHeaderOffset);
    150 
    151 		/* If any Queues' allocation failed, print error, free TxDataQueue module and exit */
    152 		if (pTxDataQ->aQueues[uQueId] == NULL)
    153 		{
    154             TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_CONSOLE , "Failed to create queue\n");
    155 			WLAN_OS_REPORT(("Failed to create queue\n"));
    156 			os_memoryFree (pTxDataQ->hOs, pTxDataQ, sizeof(TTxDataQ));
    157 			return;
    158 		}
    159 
    160 		/* Configure the Queues default values */
    161 		pTxDataQ->aQueueBusy[uQueId] = TI_FALSE;
    162         pTxDataQ->aNetStackQueueStopped[uQueId] = TI_FALSE;
    163         pTxDataQ->aTxSendPaceThresh[uQueId] = 1;
    164     }
    165 
    166     pTxDataQ->hTxSendPaceTimer = tmr_CreateTimer (pStadHandles->hTimer);
    167 	if (pTxDataQ->hTxSendPaceTimer == NULL)
    168 	{
    169         TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_ERROR, "txDataQ_Init(): Failed to create hTxSendPaceTimer!\n");
    170 		return;
    171 	}
    172 
    173     /* Register to the context engine and get the client ID */
    174     pTxDataQ->uContextId = context_RegisterClient (pTxDataQ->hContext,
    175                                                    txDataQ_RunScheduler,
    176                                                    (TI_HANDLE)pTxDataQ,
    177                                                    TI_TRUE,
    178                                                    "TX_DATA",
    179                                                    sizeof("TX_DATA"));
    180 }
    181 
    182 
    183 /**
    184  * \fn     txDataQ_SetDefaults
    185  * \brief  Configure module with default settings
    186  *
    187  * Init the Tx Data queues.
    188  * Register as the context-engine client.
    189  *
    190  * \note
    191  * \param  hTxDataQ - The object
    192  * \param  Other modules handles
    193  * \return TI_OK on success or TI_NOK on failure
    194  * \sa
    195  */
    196 TI_STATUS txDataQ_SetDefaults (TI_HANDLE  hTxDataQ, txDataInitParams_t *pTxDataInitParams)
    197 {
    198     TTxDataQ  *pTxDataQ = (TTxDataQ *)hTxDataQ;
    199 	TI_STATUS  eStatus;
    200 
    201     /* configure the classifier sub-module */
    202     eStatus = txDataClsfr_Config (hTxDataQ, &pTxDataInitParams->ClsfrInitParam);
    203     if (eStatus != TI_OK)
    204     {
    205         TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_CONSOLE ,"FATAL ERROR: txDataQ_SetDefaults(): txDataClsfr_Config failed - Aborting\n");
    206         WLAN_OS_REPORT(("FATAL ERROR: txDataQ_SetDefaults(): txDataClsfr_Config failed - Aborting\n"));
    207         return eStatus;
    208     }
    209 
    210     /* Save the module's parameters settings */
    211 	pTxDataQ->bStopNetStackTx              = pTxDataInitParams->bStopNetStackTx;
    212 	pTxDataQ->aTxSendPaceThresh[QOS_AC_BE] = pTxDataInitParams->uTxSendPaceThresh;
    213 	pTxDataQ->aTxSendPaceThresh[QOS_AC_BK] = pTxDataInitParams->uTxSendPaceThresh;
    214 	pTxDataQ->aTxSendPaceThresh[QOS_AC_VI] = pTxDataInitParams->uTxSendPaceThresh;
    215 	pTxDataQ->aTxSendPaceThresh[QOS_AC_VO] = 1;     /* Don't delay voice packts! */
    216 
    217     TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_INIT, ".....Tx Data Queue configured successfully\n");
    218 
    219     return TI_OK;
    220 }
    221 
    222 
    223 /**
    224  * \fn     txDataQ_Destroy
    225  * \brief  Destroy the module and its queues
    226  *
    227  * Clear and destroy the queues and then destroy the module object.
    228  *
    229  * \note
    230  * \param  hTxDataQ - The object
    231  * \return TI_OK - Unload succesfull, TI_NOK - Unload unsuccesfull
    232  * \sa
    233  */
    234 TI_STATUS txDataQ_Destroy (TI_HANDLE hTxDataQ)
    235 {
    236     TTxDataQ  *pTxDataQ = (TTxDataQ *)hTxDataQ;
    237     TI_STATUS  status = TI_OK;
    238     TI_UINT32  uQueId;
    239 
    240     /* Dequeue and free all queued packets */
    241     txDataQ_ClearQueues (hTxDataQ);
    242 
    243     /* Free Data queues */
    244     for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++)
    245     {
    246         if (que_Destroy(pTxDataQ->aQueues[uQueId]) != TI_OK)
    247 		{
    248             TRACE1(pTxDataQ->hReport, REPORT_SEVERITY_ERROR, "txDataQueue_unLoad: fail to free Data Queue number: %d\n",uQueId);
    249 			status = TI_NOK;
    250 		}
    251     }
    252 
    253     /* free timer */
    254     if (pTxDataQ->hTxSendPaceTimer)
    255     {
    256         tmr_DestroyTimer (pTxDataQ->hTxSendPaceTimer);
    257     }
    258 
    259     /* Free Tx Data Queue Module */
    260     os_memoryFree (pTxDataQ->hOs, pTxDataQ, sizeof(TTxDataQ));
    261 
    262     return status;
    263 }
    264 
    265 
    266 /**
    267  * \fn     txDataQ_ClearQueues
    268  * \brief  Clear all queues
    269  *
    270  * Dequeue and free all queued packets.
    271  *
    272  * \note
    273  * \param  hTxDataQ - The object
    274  * \return void
    275  * \sa
    276  */
    277 void txDataQ_ClearQueues (TI_HANDLE hTxDataQ)
    278 {
    279     TTxDataQ   *pTxDataQ = (TTxDataQ *)hTxDataQ;
    280     TTxCtrlBlk *pPktCtrlBlk;
    281     TI_UINT32  uQueId;
    282 
    283     /* Dequeue and free all queued packets */
    284     for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++)
    285     {
    286         do {
    287             context_EnterCriticalSection (pTxDataQ->hContext);
    288             pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue(pTxDataQ->aQueues[uQueId]);
    289             context_LeaveCriticalSection (pTxDataQ->hContext);
    290             if (pPktCtrlBlk != NULL) {
    291                 txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
    292             }
    293         } while (pPktCtrlBlk != NULL);
    294     }
    295 }
    296 
    297 
    298 /**
    299  * \fn     txDataQ_InsertPacket
    300  * \brief  Insert packet in queue and schedule task
    301  *
    302  * This function is called by the hard_start_xmit() callback function.
    303  * If the packet it an EAPOL, forward it to the Mgmt-Queue.
    304  * Otherwise, classify the packet, enqueue it and request
    305  *   context switch for handling it in the driver's context.
    306  *
    307  * \note
    308  * \param  hTxDataQ    - The object
    309  * \param  pPktCtrlBlk - Pointer to the packet
    310  * \param  uPacketDtag - The packet priority optionaly set by the OAL
    311  * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped.
    312  * \sa     txDataQ_Run
    313  */
    314 TI_STATUS txDataQ_InsertPacket (TI_HANDLE hTxDataQ, TTxCtrlBlk *pPktCtrlBlk, TI_UINT8 uPacketDtag)
    315 {
    316     TTxDataQ        *pTxDataQ = (TTxDataQ *)hTxDataQ;
    317 	TEthernetHeader *pEthHead = (TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]);
    318 	TI_STATUS        eStatus;
    319     TI_UINT32        uQueId;
    320     TI_UINT32        uQueSize;
    321     txCtrl_t         *pTxCtrl = (txCtrl_t *)(pTxDataQ->hTxCtrl);
    322     TI_BOOL          bRequestSchedule = TI_FALSE;
    323     TI_BOOL          bStopNetStack = TI_FALSE;
    324 	CL_TRACE_START_L3();
    325 
    326     /* If packet is EAPOL or from the generic Ethertype, forward it to the Mgmt-Queue and exit */
    327     if ((HTOWLANS(pEthHead->type) == ETHERTYPE_EAPOL) ||
    328 		(HTOWLANS(pEthHead->type) == pTxCtrl->genericEthertype))
    329     {
    330 		pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_EAPOL;
    331 
    332         return txMgmtQ_Xmit (pTxDataQ->hTxMgmtQ, pPktCtrlBlk, TI_TRUE);
    333         /* Note: The last parameter indicates that we are running in external context */
    334     }
    335 
    336     pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_ETHER;
    337 
    338     /* Enter critical section to protect classifier data and queue access */
    339     context_EnterCriticalSection (pTxDataQ->hContext);
    340 
    341 	/* Call the Classify function to set the TID field */
    342 	if (txDataClsfr_ClassifyTxPacket (hTxDataQ, pPktCtrlBlk, uPacketDtag) != TI_OK)
    343 	{
    344 #ifdef TI_DBG
    345 		pTxDataQ->uClsfrMismatchCount++;
    346 TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_WARNING, "txDataQueue_xmit: No matching classifier found \n");
    347 #endif /* TI_DBG */
    348 	}
    349 
    350 	/* Enqueue the packet in the appropriate Queue */
    351     uQueId = aTidToQueueTable[pPktCtrlBlk->tTxDescriptor.tid];
    352     eStatus = que_Enqueue (pTxDataQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);
    353 
    354     /* Get number of packets in current queue */
    355     uQueSize = que_Size (pTxDataQ->aQueues[uQueId]);
    356 
    357     /* If the current queue is not stopped */
    358     if (pTxDataQ->aQueueBusy[uQueId] == TI_FALSE)
    359     {
    360         /* If the queue has the desired number of packets, request switch to driver context for handling them */
    361         if (uQueSize == pTxDataQ->aTxSendPaceThresh[uQueId])
    362         {
    363             tmr_StopTimer (pTxDataQ->hTxSendPaceTimer);
    364             bRequestSchedule = TI_TRUE;
    365         }
    366         /* If below Tx-Send pacing threshold, start timer to trigger packets handling if expired */
    367         else if (uQueSize < pTxDataQ->aTxSendPaceThresh[uQueId])
    368         {
    369             tmr_StartTimer (pTxDataQ->hTxSendPaceTimer,
    370                             txDataQ_TxSendPaceTimeout,
    371                             hTxDataQ,
    372                             TX_SEND_PACE_TIMEOUT_MSEC,
    373                             TI_FALSE);
    374         }
    375     }
    376 
    377     /* If allowed to stop network stack and the queue is full, indicate to stop network and
    378           to schedule Tx handling (both are executed below, outside the critical section!) */
    379 	if ((pTxDataQ->bStopNetStackTx) && (uQueSize == pTxDataQ->aQueueMaxSize[uQueId]))
    380 	{
    381 		pTxDataQ->aNetStackQueueStopped[uQueId] = TI_TRUE;
    382         bRequestSchedule = TI_TRUE;
    383         bStopNetStack = TI_TRUE;
    384     }
    385 
    386     /* Leave critical section */
    387     context_LeaveCriticalSection (pTxDataQ->hContext);
    388 
    389     /* If needed, schedule Tx handling */
    390 	if (bRequestSchedule)
    391     {
    392         context_RequestSchedule (pTxDataQ->hContext, pTxDataQ->uContextId);
    393     }
    394 
    395     /* If needed, stop the network stack Tx */
    396 	if (bStopNetStack)
    397 	{
    398 		/* Stop the network stack from sending Tx packets as we have at least one date queue full.
    399 		Note that in some of the OS's (e.g Win Mobile) it is implemented by blocking the thread*/
    400 		wlanDrvIf_StopTx (pTxDataQ->hOs);
    401     }
    402 
    403 	if (eStatus != TI_OK)
    404     {
    405         /* If the packet can't be queued drop it */
    406         txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
    407 #ifdef TI_DBG
    408 		pTxDataQ->aQueueCounters[uQueId].uDroppedPacket++;
    409 #endif /* TI_DBG */
    410     }
    411 	else
    412     {
    413 #ifdef TI_DBG
    414 		pTxDataQ->aQueueCounters[uQueId].uEnqueuePacket++;
    415 #endif /* TI_DBG */
    416     }
    417 
    418     CL_TRACE_END_L3 ("tiwlan_drv.ko", "INHERIT", "TX", "");
    419 
    420     return eStatus;
    421 }
    422 
    423 
    424 /**
    425  * \fn     txDataQ_StopQueue
    426  * \brief  Set queue's busy indication
    427  *
    428  * This function is called by the txCtrl_xmitData() if the queue's backpressure
    429  *   indication is set.
    430  * It sets the internal queue's Busy indication.
    431  *
    432  * \note
    433  * \param  hTxDataQ - The object
    434  * \param  uTidBitMap   - The changed TIDs busy bitmap
    435  * \return void
    436  * \sa     txDataQ_UpdateBusyMap
    437  */
    438 void txDataQ_StopQueue (TI_HANDLE hTxDataQ, TI_UINT32 uTidBitMap)
    439 {
    440 	TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    441 
    442 	/* Set the relevant queue(s) busy flag */
    443 	txDataQ_UpdateQueuesBusyState (pTxDataQ, uTidBitMap);
    444 }
    445 
    446 
    447 /**
    448  * \fn     txDataQ_UpdateBusyMap
    449  * \brief  Set queue's busy indication
    450  *
    451  * This function is called by the txCtrl if the backpressure map per TID is changed.
    452  * This could be as a result of Tx-Complete, admission change or association.
    453  * The function modifies the internal queue's Busy indication and calls the scheduler.
    454  *
    455  * \note
    456  * \param  hTxDataQ - The object
    457  * \param  uTidBitMap   - The changed TIDs busy bitmap
    458  * \return void
    459  * \sa     txDataQ_StopQueue
    460  */
    461 void txDataQ_UpdateBusyMap (TI_HANDLE hTxDataQ, TI_UINT32 tidBitMap)
    462 {
    463 	TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    464 
    465 	/* Update the Queue(s) mode */
    466 	txDataQ_UpdateQueuesBusyState (pTxDataQ, tidBitMap);
    467 
    468 	/* Run the scheduler */
    469 	txDataQ_RunScheduler (hTxDataQ);
    470 }
    471 
    472 
    473 /**
    474  * \fn     txDataQ_StopAll
    475  * \brief  Disable Data-Queue module access to Tx path.
    476  *
    477  * Called by the Tx-Port when the data-queue module can't access the Tx path.
    478  * Sets stop-all-queues indication.
    479  *
    480  * \note
    481  * \param  hTxDataQ - The object
    482  * \return void
    483  * \sa     txDataQ_WakeAll
    484  */
    485 void txDataQ_StopAll (TI_HANDLE hTxDataQ)
    486 {
    487     TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    488 
    489 	/* Disable the data Tx port */
    490 	pTxDataQ->bDataPortEnable = TI_FALSE;
    491 }
    492 
    493 
    494 /**
    495  * \fn     txDataQ_WakeAll
    496  * \brief  Enable Data-Queue module access to Tx path.
    497  *
    498  * Called by the Tx-Port when the data-queue module can access the Tx path.
    499  * Clears the stop-all-queues indication and calls the scheduler.
    500  *
    501  * \note
    502  * \param  hTxDataQ - The object
    503  * \return void
    504  * \sa     txDataQ_StopAll
    505  */
    506 void txDataQ_WakeAll (TI_HANDLE hTxDataQ)
    507 {
    508     TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    509 
    510 	/* Enable the data Tx port */
    511 	pTxDataQ->bDataPortEnable = TI_TRUE;
    512 
    513 	/* Run the scheduler */
    514 	txDataQ_RunScheduler (hTxDataQ);
    515 }
    516 
    517 
    518 /***************************************************************************
    519 *                       DEBUG  FUNCTIONS  IMPLEMENTATION			       *
    520 ****************************************************************************/
    521 
    522 #ifdef TI_DBG
    523 
    524 /**
    525  * \fn     txDataQ_PrintModuleParams
    526  * \brief  Print Module Parameters
    527  *
    528  * Print Module Parameters
    529  *
    530  * \note
    531  * \param  hTxDataQ - The object
    532  * \return void
    533  * \sa
    534  */
    535 void txDataQ_PrintModuleParams (TI_HANDLE hTxDataQ)
    536 {
    537 	TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    538 	TI_UINT32      qIndex;
    539 
    540 	WLAN_OS_REPORT(("--------- txDataQueue_printModuleParams ----------\n\n"));
    541 
    542 	WLAN_OS_REPORT(("bStopNetStackTx = %d\n",pTxDataQ->bStopNetStackTx));
    543 	WLAN_OS_REPORT(("bDataPortEnable = %d\n",pTxDataQ->bDataPortEnable));
    544 	WLAN_OS_REPORT(("uNumQueues      = %d\n",pTxDataQ->uNumQueues));
    545 	WLAN_OS_REPORT(("uLastQueId      = %d\n",pTxDataQ->uLastQueId));
    546 	WLAN_OS_REPORT(("uContextId      = %d\n",pTxDataQ->uContextId));
    547 
    548 	for (qIndex = 0; qIndex < pTxDataQ->uNumQueues; qIndex++)
    549     {
    550 		WLAN_OS_REPORT(("aQueueBusy[%d]            = %d\n", qIndex, pTxDataQ->aQueueBusy[qIndex]));
    551     }
    552 	for (qIndex = 0; qIndex < pTxDataQ->uNumQueues; qIndex++)
    553     {
    554         WLAN_OS_REPORT(("aQueueMaxSize[%d]         = %d\n", qIndex, pTxDataQ->aQueueMaxSize[qIndex]));
    555     }
    556 	for (qIndex = 0; qIndex < pTxDataQ->uNumQueues; qIndex++)
    557     {
    558         WLAN_OS_REPORT(("aTxSendPaceThresh[%d]     = %d\n", qIndex, pTxDataQ->aTxSendPaceThresh[qIndex]));
    559     }
    560 	for (qIndex = 0; qIndex < pTxDataQ->uNumQueues; qIndex++)
    561     {
    562         WLAN_OS_REPORT(("aNetStackQueueStopped[%d] = %d\n", qIndex, pTxDataQ->aNetStackQueueStopped[qIndex]));
    563     }
    564 
    565 	WLAN_OS_REPORT(("-------------- Queues Info -----------------------\n"));
    566 	for (qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++)
    567     {
    568         WLAN_OS_REPORT(("Que %d:\n", qIndex));
    569         que_Print (pTxDataQ->aQueues[qIndex]);
    570     }
    571 
    572 	WLAN_OS_REPORT(("--------------------------------------------------\n\n"));
    573 }
    574 
    575 
    576 /**
    577  * \fn     txDataQ_PrintQueueStatistics
    578  * \brief  Print queues statistics
    579  *
    580  * Print queues statistics
    581  *
    582  * \note
    583  * \param  hTxDataQ - The object
    584  * \return void
    585  * \sa
    586  */
    587 void txDataQ_PrintQueueStatistics (TI_HANDLE hTxDataQ)
    588 {
    589 #ifdef REPORT_LOG
    590     TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    591     TI_UINT32      qIndex;
    592 
    593     WLAN_OS_REPORT(("-------------- txDataQueue_printStatistics -------\n\n"));
    594 
    595 	WLAN_OS_REPORT(("uClsfrMismatchCount      = %d\n",pTxDataQ->uClsfrMismatchCount));
    596     WLAN_OS_REPORT(("uTxSendPaceTimeoutsCount = %d\n",pTxDataQ->uTxSendPaceTimeoutsCount));
    597 
    598     WLAN_OS_REPORT(("-------------- Enqueue to queues -----------------\n"));
    599     for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++)
    600         WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uEnqueuePacket));
    601 
    602     WLAN_OS_REPORT(("-------------- Dequeue from queues ---------------\n"));
    603     for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++)
    604         WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uDequeuePacket));
    605 
    606     WLAN_OS_REPORT(("-------------- Requeue to queues -----------------\n"));
    607     for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++)
    608         WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uRequeuePacket));
    609 
    610     WLAN_OS_REPORT(("-------------- Sent to TxCtrl --------------------\n"));
    611     for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++)
    612         WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uXmittedPacket));
    613 
    614     WLAN_OS_REPORT(("-------------- Dropped - Queue Full --------------\n"));
    615     for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++)
    616         WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uDroppedPacket));
    617 
    618     WLAN_OS_REPORT(("--------------------------------------------------\n\n"));
    619 #endif
    620 }
    621 
    622 
    623 /**
    624  * \fn     txDataQ_ResetQueueStatistics
    625  * \brief  Reset queues statistics
    626  *
    627  * Reset queues statistics
    628  *
    629  * \note
    630  * \param  hTxDataQ - The object
    631  * \return void
    632  * \sa
    633  */
    634 void txDataQ_ResetQueueStatistics (TI_HANDLE hTxDataQ)
    635 {
    636 	TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    637 
    638     os_memoryZero(pTxDataQ->hOs, &pTxDataQ->aQueueCounters, sizeof(pTxDataQ->aQueueCounters));
    639     pTxDataQ->uTxSendPaceTimeoutsCount = 0;
    640 }
    641 
    642 
    643 #endif /* TI_DBG */
    644 
    645 
    646 
    647 /***************************************************************************
    648 *                      INTERNAL  FUNCTIONS  IMPLEMENTATION				   *
    649 ****************************************************************************/
    650 
    651 
    652 /**
    653  * \fn     txDataQ_RunScheduler
    654  * \brief  The module's Tx scheduler
    655  *
    656  * This function is the Data-Queue scheduler.
    657  * It selects a packet to transmit from the tx queues and sends it to the TxCtrl.
    658  * The queues are selected in a round-robin order.
    659  * The function is called by one of:
    660  *     txDataQ_Run()
    661  *     txDataQ_UpdateBusyMap()
    662  *     txDataQ_WakeAll()
    663  *
    664  * \note
    665  * \param  hTxDataQ - The object
    666  * \return void
    667  * \sa
    668  */
    669 static void txDataQ_RunScheduler (TI_HANDLE hTxDataQ)
    670 {
    671 	TTxDataQ   *pTxDataQ = (TTxDataQ *)hTxDataQ;
    672 	TI_UINT32  uIdleIterationsCount = 0;  /* Count iterations without packet transmission (for exit criteria) */
    673 	TI_UINT32  uQueId = pTxDataQ->uLastQueId;  /* The last iteration queue */
    674 	EStatusXmit eStatus;  /* The return status of the txCtrl_xmitData function */
    675     TTxCtrlBlk *pPktCtrlBlk; /* Pointer to the packet to be dequeued and sent */
    676 
    677 	while(1)
    678 	{
    679 		/* If the Data port is closed or the scheduler couldn't send packets from
    680 		     all queues, indicate end of current packets burst and exit */
    681 		if ( !pTxDataQ->bDataPortEnable  ||  (uIdleIterationsCount >= pTxDataQ->uNumQueues) )
    682 		{
    683             TWD_txXfer_EndOfBurst (pTxDataQ->hTWD);
    684 			return;
    685 		}
    686 
    687 		/* Selecting the next queue */
    688 		uQueId++;
    689 		if (uQueId == pTxDataQ->uNumQueues)
    690         {
    691 			uQueId = 0;
    692         }
    693 		pTxDataQ->uLastQueId = uQueId;
    694 
    695 		/* Increment the idle iterations counter */
    696 		uIdleIterationsCount++;
    697 
    698 		/* If the queue is busy (AC is full), continue to next queue. */
    699 		if (pTxDataQ->aQueueBusy[uQueId])
    700         {
    701 			continue;
    702         }
    703 
    704 		/* Dequeue a packet in a critical section */
    705         context_EnterCriticalSection (pTxDataQ->hContext);
    706 		pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pTxDataQ->aQueues[uQueId]);
    707         context_LeaveCriticalSection (pTxDataQ->hContext);
    708 
    709 		/* If the queue was empty, continue to the next queue */
    710 		if (pPktCtrlBlk == NULL)
    711         {
    712 			if ((pTxDataQ->bStopNetStackTx) && pTxDataQ->aNetStackQueueStopped[uQueId])
    713 			{
    714 				pTxDataQ->aNetStackQueueStopped[uQueId] = TI_FALSE;
    715 				/*Resume the TX process as our date queues are empty*/
    716 				wlanDrvIf_ResumeTx (pTxDataQ->hOs);
    717 			}
    718 
    719 			continue;
    720         }
    721 
    722 #ifdef TI_DBG
    723 		pTxDataQ->aQueueCounters[uQueId].uDequeuePacket++;
    724 #endif /* TI_DBG */
    725 
    726 		/* Send the packet */
    727 		eStatus = txCtrl_XmitData (pTxDataQ->hTxCtrl, pPktCtrlBlk);
    728 
    729 		/*
    730          * If the return status is busy it means that the packet was not sent
    731          *   so we need to requeue it for future try.
    732          */
    733 		if(eStatus == STATUS_XMIT_BUSY)
    734 		{
    735             TI_STATUS eQueStatus;
    736 
    737             /* Requeue the packet in a critical section */
    738             context_EnterCriticalSection (pTxDataQ->hContext);
    739 			eQueStatus = que_Requeue (pTxDataQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk);
    740             if (eQueStatus != TI_OK)
    741             {
    742                 /* If the packet can't be queued drop it */
    743                 /* Note: may happen only if this thread was preempted between the
    744                    dequeue and requeue and new packets were inserted into this quque */
    745                 txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK);
    746 #ifdef TI_DBG
    747                 pTxDataQ->aQueueCounters[uQueId].uDroppedPacket++;
    748 #endif /* TI_DBG */
    749             }
    750             context_LeaveCriticalSection (pTxDataQ->hContext);
    751 
    752 #ifdef TI_DBG
    753 			pTxDataQ->aQueueCounters[uQueId].uRequeuePacket++;
    754 #endif /* TI_DBG */
    755 
    756 			continue;
    757 		}
    758 
    759 		/* If we reach this point, a packet was sent successfully so reset the idle iterations counter. */
    760 		uIdleIterationsCount = 0;
    761 
    762 #ifdef TI_DBG
    763 		pTxDataQ->aQueueCounters[uQueId].uXmittedPacket++;
    764 #endif /* TI_DBG */
    765 
    766 	} /* End of while */
    767 
    768 	/* Unreachable code */
    769 }
    770 
    771 
    772 /**
    773  * \fn     txDataQ_UpdateQueuesBusyState
    774  * \brief  Update queues' busy state
    775  *
    776  * Update the Queues Mode to Busy according to the input TidBitMap.
    777 *               Each Tid that is set indicates that the related Queue is Busy.
    778 *
    779  * \note
    780  * \param  hTxDataQ - The object
    781  * \param  uTidBitMap   - The changed TIDs busy bitmap
    782  * \return void
    783  * \sa
    784  */
    785 static void txDataQ_UpdateQueuesBusyState (TTxDataQ *pTxDataQ, TI_UINT32 uTidBitMap)
    786 {
    787 	TI_UINT32 uTidIdx;
    788 
    789 	/* Go over the TidBitMap and update the related queue busy state */
    790 	for (uTidIdx = 0; uTidIdx < MAX_NUM_OF_802_1d_TAGS; uTidIdx++, uTidBitMap >>= 1)
    791 	{
    792 		if (uTidBitMap & 0x1) /* this Tid is busy */
    793         {
    794 			pTxDataQ->aQueueBusy[aTidToQueueTable[uTidIdx]] = TI_TRUE;
    795         }
    796 		else
    797         {
    798 			pTxDataQ->aQueueBusy[aTidToQueueTable[uTidIdx]] = TI_FALSE;
    799         }
    800 	}
    801 }
    802 
    803 
    804 /*
    805  * \brief   Handle Tx-Send-Pacing timeout.
    806  *
    807  * \param  hTxDataQ        - Module handle
    808  * \param  bTwdInitOccured - Indicate if TWD restart (recovery) occured
    809  * \return void
    810  *
    811  * \par Description
    812  * Call the Tx scheduler to handle the queued packets.
    813  *
    814  * \sa
    815  */
    816 static void txDataQ_TxSendPaceTimeout (TI_HANDLE hTxDataQ, TI_BOOL bTwdInitOccured)
    817 {
    818 	TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ;
    819 
    820     pTxDataQ->uTxSendPaceTimeoutsCount++;
    821 
    822     txDataQ_RunScheduler (hTxDataQ);
    823 }
    824