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