• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
txDataQ_Create(TI_HANDLE hOs)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  */
txDataQ_Init(TStadHandlesList * pStadHandles)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  */
txDataQ_SetDefaults(TI_HANDLE hTxDataQ,txDataInitParams_t * pTxDataInitParams)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  */
txDataQ_Destroy(TI_HANDLE hTxDataQ)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  */
txDataQ_ClearQueues(TI_HANDLE hTxDataQ)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  */
txDataQ_InsertPacket(TI_HANDLE hTxDataQ,TTxCtrlBlk * pPktCtrlBlk,TI_UINT8 uPacketDtag)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  */
txDataQ_StopQueue(TI_HANDLE hTxDataQ,TI_UINT32 uTidBitMap)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  */
txDataQ_UpdateBusyMap(TI_HANDLE hTxDataQ,TI_UINT32 tidBitMap)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  */
txDataQ_StopAll(TI_HANDLE hTxDataQ)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  */
txDataQ_WakeAll(TI_HANDLE hTxDataQ)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  */
txDataQ_PrintModuleParams(TI_HANDLE hTxDataQ)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  */
txDataQ_PrintQueueStatistics(TI_HANDLE hTxDataQ)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  */
txDataQ_ResetQueueStatistics(TI_HANDLE hTxDataQ)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  */
txDataQ_RunScheduler(TI_HANDLE hTxDataQ)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  */
txDataQ_UpdateQueuesBusyState(TTxDataQ * pTxDataQ,TI_UINT32 uTidBitMap)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  */
txDataQ_TxSendPaceTimeout(TI_HANDLE hTxDataQ,TI_BOOL bTwdInitOccured)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