1 /* 2 * txDataQueue.c 3 * 4 * Copyright(c) 1998 - 2009 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 "queue.h" 47 #include "context.h" 48 #include "Ethernet.h" 49 #include "TWDriver.h" 50 #include "DataCtrl_Api.h" 51 #include "txDataQueue.h" 52 #include "DrvMainModules.h" 53 #include "bmtrace_api.h" 54 55 56 /* Internal Functions prototypes */ 57 static void txDataQ_RunScheduler (TI_HANDLE hTxDataQ); 58 static void txDataQ_UpdateQueuesBusyState (TTxDataQ *pTxDataQ, TI_UINT32 uTidBitMap); 59 60 61 /*************************************************************************** 62 * PUBLIC FUNCTIONS IMPLEMENTATION * 63 ****************************************************************************/ 64 65 66 /** 67 * \fn txDataQ_Create 68 * \brief Create the module and its queues 69 * 70 * Create the Tx Data module and its queues. 71 * 72 * \note 73 * \param hOs - Handle to the Os Abstraction Layer 74 * \return Handle to the allocated Tx Data Queue module (NULL if failed) 75 * \sa 76 */ 77 TI_HANDLE txDataQ_Create(TI_HANDLE hOs) 78 { 79 TTxDataQ *pTxDataQ; 80 81 /* allocate TxDataQueue module */ 82 pTxDataQ = os_memoryAlloc (hOs, (sizeof(TTxDataQ))); 83 84 if (!pTxDataQ) 85 { 86 WLAN_OS_REPORT(("Error allocating the TxDataQueue Module\n")); 87 return NULL; 88 } 89 90 /* Reset TxDataQueue module */ 91 os_memoryZero (hOs, pTxDataQ, (sizeof(TTxDataQ))); 92 93 return (TI_HANDLE)pTxDataQ; 94 } 95 96 97 /** 98 * \fn txDataQ_Init 99 * \brief Save required modules handles 100 * 101 * Save other modules handles. 102 * 103 * \note 104 * \param pStadHandles - The driver modules handles 105 * \return void 106 * \sa 107 */ 108 void txDataQ_Init (TStadHandlesList *pStadHandles) 109 { 110 TTxDataQ *pTxDataQ = (TTxDataQ *)(pStadHandles->hTxDataQ); 111 TI_UINT32 uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode); 112 TI_UINT8 uQueId; 113 114 /* save modules handles */ 115 pTxDataQ->hContext = pStadHandles->hContext; 116 pTxDataQ->hTxCtrl = pStadHandles->hTxCtrl; 117 pTxDataQ->hOs = pStadHandles->hOs; 118 pTxDataQ->hReport = pStadHandles->hReport; 119 pTxDataQ->hTxMgmtQ = pStadHandles->hTxMgmtQ; 120 121 /* Configures the Port Default status to Close */ 122 pTxDataQ->bDataPortEnable = TI_FALSE; 123 124 /* Configures the LastQueId to zero => scheduler will strart from Queue 1*/ 125 pTxDataQ->uLastQueId = 0; 126 127 /* init the number of the Data queue to be used */ 128 pTxDataQ->uNumQueues = MAX_NUM_OF_AC; 129 130 /* init the max size of the Data queues */ 131 pTxDataQ->aQueueMaxSize[QOS_AC_BE] = DATA_QUEUE_DEPTH_BE; 132 pTxDataQ->aQueueMaxSize[QOS_AC_BK] = DATA_QUEUE_DEPTH_BK; 133 pTxDataQ->aQueueMaxSize[QOS_AC_VI] = DATA_QUEUE_DEPTH_VI; 134 pTxDataQ->aQueueMaxSize[QOS_AC_VO] = DATA_QUEUE_DEPTH_VO; 135 136 /* Create the tx data queues */ 137 for (uQueId = 0; uQueId < pTxDataQ->uNumQueues; uQueId++) 138 { 139 pTxDataQ->aQueues[uQueId] = que_Create (pTxDataQ->hOs, 140 pTxDataQ->hReport, 141 pTxDataQ->aQueueMaxSize[uQueId], 142 uNodeHeaderOffset); 143 144 /* If any Queues' allocation failed, print error, free TxDataQueue module and exit */ 145 if (pTxDataQ->aQueues[uQueId] == NULL) 146 { 147 TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_CONSOLE , "Failed to create queue\n"); 148 WLAN_OS_REPORT(("Failed to create queue\n")); 149 os_memoryFree (pTxDataQ->hOs, pTxDataQ, sizeof(TTxDataQ)); 150 return; 151 } 152 153 /* Configure the Queue default Mode to Open (not busy)*/ 154 pTxDataQ->aQueueBusy[uQueId] = TI_FALSE; 155 } 156 157 /* Register to the context engine and get the client ID */ 158 pTxDataQ->uContextId = context_RegisterClient (pTxDataQ->hContext, 159 txDataQ_RunScheduler, 160 (TI_HANDLE)pTxDataQ, 161 TI_TRUE, 162 "TX_DATA", 163 sizeof("TX_DATA")); 164 } 165 166 167 /** 168 * \fn txDataQ_SetDefaults 169 * \brief Configure module with default settings 170 * 171 * Init the Tx Data queues. 172 * Register as the context-engine client. 173 * 174 * \note 175 * \param hTxDataQ - The object 176 * \param Other modules handles 177 * \return TI_OK on success or TI_NOK on failure 178 * \sa 179 */ 180 TI_STATUS txDataQ_SetDefaults (TI_HANDLE hTxDataQ, txDataInitParams_t *pTxDataInitParams) 181 { 182 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 183 TI_STATUS eStatus; 184 185 /* configure the classifier sub-module */ 186 eStatus = txDataClsfr_Config (hTxDataQ, &pTxDataInitParams->ClsfrInitParam); 187 if (eStatus != TI_OK) 188 { 189 TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_CONSOLE ,"FATAL ERROR: txDataQ_SetDefaults(): txDataClsfr_Config failed - Aborting\n"); 190 WLAN_OS_REPORT(("FATAL ERROR: txDataQ_SetDefaults(): txDataClsfr_Config failed - Aborting\n")); 191 return eStatus; 192 } 193 194 TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_INIT, ".....Tx Data Queue configured successfully\n"); 195 196 return TI_OK; 197 } 198 199 200 /** 201 * \fn txDataQ_Destroy 202 * \brief Destroy the module and its queues 203 * 204 * Clear and destroy the queues and then destroy the module object. 205 * 206 * \note 207 * \param hTxDataQ - The object 208 * \return TI_OK - Unload succesfull, TI_NOK - Unload unsuccesfull 209 * \sa 210 */ 211 TI_STATUS txDataQ_Destroy (TI_HANDLE hTxDataQ) 212 { 213 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 214 TI_STATUS status = TI_OK; 215 TI_UINT32 uQueId; 216 217 /* Dequeue and free all queued packets */ 218 txDataQ_ClearQueues (hTxDataQ); 219 220 /* Free Data queues */ 221 for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++) 222 { 223 if (que_Destroy(pTxDataQ->aQueues[uQueId]) != TI_OK) 224 { 225 TRACE1(pTxDataQ->hReport, REPORT_SEVERITY_ERROR, "txDataQueue_unLoad: fail to free Data Queue number: %d\n",uQueId); 226 status = TI_NOK; 227 } 228 } 229 230 /* Free Tx Data Queue Module */ 231 os_memoryFree (pTxDataQ->hOs, pTxDataQ, sizeof(TTxDataQ)); 232 233 return status; 234 } 235 236 237 /** 238 * \fn txDataQ_ClearQueues 239 * \brief Clear all queues 240 * 241 * Dequeue and free all queued packets. 242 * 243 * \note 244 * \param hTxDataQ - The object 245 * \return void 246 * \sa 247 */ 248 void txDataQ_ClearQueues (TI_HANDLE hTxDataQ) 249 { 250 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 251 TTxCtrlBlk *pPktCtrlBlk; 252 TI_UINT32 uQueId; 253 254 /* Dequeue and free all queued packets */ 255 for (uQueId = 0 ; uQueId < pTxDataQ->uNumQueues ; uQueId++) 256 { 257 do { 258 context_EnterCriticalSection (pTxDataQ->hContext); 259 pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue(pTxDataQ->aQueues[uQueId]); 260 context_LeaveCriticalSection (pTxDataQ->hContext); 261 if (pPktCtrlBlk != NULL) { 262 txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); 263 } 264 } while (pPktCtrlBlk != NULL); 265 } 266 } 267 268 269 /** 270 * \fn txDataQ_InsertPacket 271 * \brief Insert packet in queue and schedule task 272 * 273 * This function is called by the hard_start_xmit() callback function. 274 * If the packet it an EAPOL, forward it to the Mgmt-Queue. 275 * Otherwise, classify the packet, enqueue it and request 276 * context switch for handling it in the driver's context. 277 * 278 * \note 279 * \param hTxDataQ - The object 280 * \param pPktCtrlBlk - Pointer to the packet 281 * \param uPacketDtag - The packet priority optionaly set by the OAL 282 * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped. 283 * \sa txDataQ_Run 284 */ 285 TI_STATUS txDataQ_InsertPacket (TI_HANDLE hTxDataQ, TTxCtrlBlk *pPktCtrlBlk, TI_UINT8 uPacketDtag) 286 { 287 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 288 TEthernetHeader *pEthHead = (TEthernetHeader *)(pPktCtrlBlk->tTxnStruct.aBuf[0]); 289 TI_STATUS eStatus; 290 TI_UINT32 uQueId; 291 TI_UINT32 uQueSize; 292 CL_TRACE_START_L3(); 293 294 /* If packet is EAPOL, forward it to the Mgmt-Queue and exit */ 295 if (HTOWLANS(pEthHead->type) == ETHERTYPE_EAPOL) 296 { 297 pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_EAPOL; 298 299 return txMgmtQ_Xmit (pTxDataQ->hTxMgmtQ, pPktCtrlBlk, TI_TRUE); 300 /* Note: The last parameter indicates that we are running in external context */ 301 } 302 303 pPktCtrlBlk->tTxPktParams.uPktType = TX_PKT_TYPE_ETHER; 304 305 /* Enter critical section to protect classifier data and queue access */ 306 context_EnterCriticalSection (pTxDataQ->hContext); 307 308 /* Call the Classify function to set the TID field */ 309 if (txDataClsfr_ClassifyTxPacket (hTxDataQ, pPktCtrlBlk, uPacketDtag) != TI_OK) 310 { 311 #ifdef TI_DBG 312 pTxDataQ->uClsfrMismatchCount++; 313 TRACE0(pTxDataQ->hReport, REPORT_SEVERITY_WARNING, "txDataQueue_xmit: No matching classifier found \n"); 314 #endif /* TI_DBG */ 315 } 316 317 /* Enqueue the packet in the appropriate Queue */ 318 uQueId = aTidToQueueTable[pPktCtrlBlk->tTxDescriptor.tid]; 319 eStatus = que_Enqueue (pTxDataQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); 320 321 /* Get number of packets in current queue */ 322 uQueSize = que_Size (pTxDataQ->aQueues[uQueId]); 323 324 /* Leave critical section */ 325 context_LeaveCriticalSection (pTxDataQ->hContext); 326 327 /* If the queue was empty, request switch to driver context for handling queued packet(s) */ 328 if (uQueSize == 1) 329 { 330 context_RequestSchedule (pTxDataQ->hContext, pTxDataQ->uContextId); 331 } 332 333 if (eStatus != TI_OK) 334 { 335 /* If the packet can't be queued drop it */ 336 txCtrl_FreePacket (pTxDataQ->hTxCtrl, pPktCtrlBlk, TI_NOK); 337 #ifdef TI_DBG 338 pTxDataQ->aQueueCounters[uQueId].uDroppedPacket++; 339 #endif /* TI_DBG */ 340 } 341 else 342 { 343 #ifdef TI_DBG 344 pTxDataQ->aQueueCounters[uQueId].uEnqueuePacket++; 345 #endif /* TI_DBG */ 346 } 347 348 CL_TRACE_END_L3 ("tiwlan_drv.ko", "INHERIT", "TX", ""); 349 350 return eStatus; 351 } 352 353 354 /** 355 * \fn txDataQ_StopQueue 356 * \brief Set queue's busy indication 357 * 358 * This function is called by the txCtrl_xmitData() if the queue's backpressure 359 * indication is set. 360 * It sets the internal queue's Busy indication. 361 * 362 * \note 363 * \param hTxDataQ - The object 364 * \param uTidBitMap - The changed TIDs busy bitmap 365 * \return void 366 * \sa txDataQ_UpdateBusyMap 367 */ 368 void txDataQ_StopQueue (TI_HANDLE hTxDataQ, TI_UINT32 uTidBitMap) 369 { 370 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 371 372 /* Set the relevant queue(s) busy flag */ 373 txDataQ_UpdateQueuesBusyState (pTxDataQ, uTidBitMap); 374 } 375 376 377 /** 378 * \fn txDataQ_UpdateBusyMap 379 * \brief Set queue's busy indication 380 * 381 * This function is called by the txCtrl if the backpressure map per TID is changed. 382 * This could be as a result of Tx-Complete, admission change or association. 383 * The function modifies the internal queue's Busy indication and calls the scheduler. 384 * 385 * \note 386 * \param hTxDataQ - The object 387 * \param uTidBitMap - The changed TIDs busy bitmap 388 * \return void 389 * \sa txDataQ_StopQueue 390 */ 391 void txDataQ_UpdateBusyMap (TI_HANDLE hTxDataQ, TI_UINT32 tidBitMap) 392 { 393 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 394 395 /* Update the Queue(s) mode */ 396 txDataQ_UpdateQueuesBusyState (pTxDataQ, tidBitMap); 397 398 /* Run the scheduler */ 399 txDataQ_RunScheduler (hTxDataQ); 400 } 401 402 403 /** 404 * \fn txDataQ_StopAll 405 * \brief Disable Data-Queue module access to Tx path. 406 * 407 * Called by the Tx-Port when the data-queue module can't access the Tx path. 408 * Sets stop-all-queues indication. 409 * 410 * \note 411 * \param hTxDataQ - The object 412 * \return void 413 * \sa txDataQ_WakeAll 414 */ 415 void txDataQ_StopAll (TI_HANDLE hTxDataQ) 416 { 417 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 418 419 /* Disable the data Tx port */ 420 pTxDataQ->bDataPortEnable = TI_FALSE; 421 } 422 423 424 /** 425 * \fn txDataQ_WakeAll 426 * \brief Enable Data-Queue module access to Tx path. 427 * 428 * Called by the Tx-Port when the data-queue module can access the Tx path. 429 * Clears the stop-all-queues indication and calls the scheduler. 430 * 431 * \note 432 * \param hTxDataQ - The object 433 * \return void 434 * \sa txDataQ_StopAll 435 */ 436 void txDataQ_WakeAll (TI_HANDLE hTxDataQ) 437 { 438 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 439 440 /* Enable the data Tx port */ 441 pTxDataQ->bDataPortEnable = TI_TRUE; 442 443 /* Run the scheduler */ 444 txDataQ_RunScheduler (hTxDataQ); 445 } 446 447 448 /*************************************************************************** 449 * DEBUG FUNCTIONS IMPLEMENTATION * 450 ****************************************************************************/ 451 452 #ifdef TI_DBG 453 454 /** 455 * \fn txDataQ_PrintModuleParams 456 * \brief Print Module Parameters 457 * 458 * Print Module Parameters 459 * 460 * \note 461 * \param hTxDataQ - The object 462 * \return void 463 * \sa 464 */ 465 void txDataQ_PrintModuleParams (TI_HANDLE hTxDataQ) 466 { 467 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 468 TI_UINT32 qIndex; 469 470 WLAN_OS_REPORT(("--------- txDataQueue_printModuleParams ----------\n\n")); 471 472 WLAN_OS_REPORT(("bDataPortEnable = %d\n",pTxDataQ->bDataPortEnable)); 473 WLAN_OS_REPORT(("uNumQueues = %d\n",pTxDataQ->uNumQueues)); 474 WLAN_OS_REPORT(("uLastQueId = %d\n",pTxDataQ->uLastQueId)); 475 WLAN_OS_REPORT(("uContextId = %d\n",pTxDataQ->uContextId)); 476 477 for (qIndex = 0; qIndex < pTxDataQ->uNumQueues; qIndex++) 478 { 479 WLAN_OS_REPORT(("aQueueBusy[%d] = %d\n", qIndex, pTxDataQ->aQueueBusy[qIndex])); 480 WLAN_OS_REPORT(("aQueueMaxSize[%d] = %d\n", qIndex, pTxDataQ->aQueueMaxSize[qIndex])); 481 } 482 483 WLAN_OS_REPORT(("-------------- Queues Info -----------------------\n")); 484 for (qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++) 485 { 486 WLAN_OS_REPORT(("Que %d:\n", qIndex)); 487 que_Print (pTxDataQ->aQueues[qIndex]); 488 } 489 490 WLAN_OS_REPORT(("--------------------------------------------------\n\n")); 491 } 492 493 494 /** 495 * \fn txDataQ_PrintQueueStatistics 496 * \brief Print queues statistics 497 * 498 * Print queues statistics 499 * 500 * \note 501 * \param hTxDataQ - The object 502 * \return void 503 * \sa 504 */ 505 void txDataQ_PrintQueueStatistics (TI_HANDLE hTxDataQ) 506 { 507 #ifdef REPORT_LOG 508 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 509 TI_UINT32 qIndex; 510 511 WLAN_OS_REPORT(("-------------- txDataQueue_printStatistics -------\n\n")); 512 513 WLAN_OS_REPORT(("-------------- Classifier Mismatches = %d -------\n",pTxDataQ->uClsfrMismatchCount)); 514 515 WLAN_OS_REPORT(("-------------- Enqueue to queues -----------------\n")); 516 for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++) 517 WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uEnqueuePacket)); 518 519 WLAN_OS_REPORT(("-------------- Dequeue from queues ---------------\n")); 520 for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++) 521 WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uDequeuePacket)); 522 523 WLAN_OS_REPORT(("-------------- Requeue to queues -----------------\n")); 524 for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++) 525 WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uRequeuePacket)); 526 527 WLAN_OS_REPORT(("-------------- Sent to TxCtrl --------------------\n")); 528 for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++) 529 WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uXmittedPacket)); 530 531 WLAN_OS_REPORT(("-------------- Dropped - Queue Full --------------\n")); 532 for(qIndex = 0; qIndex < MAX_NUM_OF_AC; qIndex++) 533 WLAN_OS_REPORT(("Que[%d]: = %d\n",qIndex, pTxDataQ->aQueueCounters[qIndex].uDroppedPacket)); 534 535 WLAN_OS_REPORT(("--------------------------------------------------\n\n")); 536 #endif 537 } 538 539 540 /** 541 * \fn txDataQ_ResetQueueStatistics 542 * \brief Reset queues statistics 543 * 544 * Reset queues statistics 545 * 546 * \note 547 * \param hTxDataQ - The object 548 * \return void 549 * \sa 550 */ 551 void txDataQ_ResetQueueStatistics (TI_HANDLE hTxDataQ) 552 { 553 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 554 555 os_memoryZero(pTxDataQ->hOs, &pTxDataQ->aQueueCounters, sizeof(pTxDataQ->aQueueCounters)); 556 } 557 558 559 #endif /* TI_DBG */ 560 561 562 563 /*************************************************************************** 564 * INTERNAL FUNCTIONS IMPLEMENTATION * 565 ****************************************************************************/ 566 567 568 /** 569 * \fn txDataQ_RunScheduler 570 * \brief The module's Tx scheduler 571 * 572 * This function is the Data-Queue scheduler. 573 * It selects a packet to transmit from the tx queues and sends it to the TxCtrl. 574 * The queues are selected in a round-robin order. 575 * The function is called by one of: 576 * txDataQ_Run() 577 * txDataQ_UpdateBusyMap() 578 * txDataQ_WakeAll() 579 * 580 * \note 581 * \param hTxDataQ - The object 582 * \return void 583 * \sa 584 */ 585 static void txDataQ_RunScheduler (TI_HANDLE hTxDataQ) 586 { 587 TTxDataQ *pTxDataQ = (TTxDataQ *)hTxDataQ; 588 TI_UINT32 uIdleIterationsCount = 0; /* Count iterations without packet transmission (for exit criteria) */ 589 TI_UINT32 uQueId = pTxDataQ->uLastQueId; /* The last iteration queue */ 590 TI_STATUS eStatus; /* The return status of the txCtrl_xmitData function */ 591 TTxCtrlBlk *pPktCtrlBlk; /* Pointer to the packet to be dequeued and sent */ 592 593 while(1) 594 { 595 /* check if the Data port is closed or if the scheduler couldn't send packet from 596 all queues => no packet can be transferred to the TNET */ 597 if ( !pTxDataQ->bDataPortEnable || (uIdleIterationsCount >= pTxDataQ->uNumQueues) ) 598 { 599 return; 600 } 601 602 /* Selecting the next queue */ 603 uQueId++; 604 if (uQueId == pTxDataQ->uNumQueues) 605 { 606 uQueId = 0; 607 } 608 pTxDataQ->uLastQueId = uQueId; 609 610 /* Increment the idle iterations counter */ 611 uIdleIterationsCount++; 612 613 /* If the queue is busy (AC is full), continue to next queue. */ 614 if (pTxDataQ->aQueueBusy[uQueId]) 615 { 616 continue; 617 } 618 619 /* Dequeue a packet in a critical section */ 620 context_EnterCriticalSection (pTxDataQ->hContext); 621 pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pTxDataQ->aQueues[uQueId]); 622 context_LeaveCriticalSection (pTxDataQ->hContext); 623 624 /* If the queue was empty, continue to the next queue */ 625 if (pPktCtrlBlk == NULL) 626 { 627 continue; 628 } 629 630 #ifdef TI_DBG 631 pTxDataQ->aQueueCounters[uQueId].uDequeuePacket++; 632 #endif /* TI_DBG */ 633 634 /* Send the packet */ 635 eStatus = txCtrl_XmitData (pTxDataQ->hTxCtrl, pPktCtrlBlk); 636 637 /* 638 * If the return status is busy it means that the packet was not sent 639 * so we need to requeue it for future try. 640 */ 641 if(eStatus == STATUS_XMIT_BUSY) 642 { 643 /* Requeue the packet in a critical section */ 644 context_EnterCriticalSection (pTxDataQ->hContext); 645 que_Requeue (pTxDataQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); 646 context_LeaveCriticalSection (pTxDataQ->hContext); 647 648 #ifdef TI_DBG 649 pTxDataQ->aQueueCounters[uQueId].uRequeuePacket++; 650 #endif /* TI_DBG */ 651 652 continue; 653 } 654 655 /* If we reach this point, a packet was sent successfully so reset the idle iterations counter. */ 656 uIdleIterationsCount = 0; 657 658 #ifdef TI_DBG 659 pTxDataQ->aQueueCounters[uQueId].uXmittedPacket++; 660 #endif /* TI_DBG */ 661 662 } /* End of while */ 663 664 /* Unreachable code */ 665 } 666 667 668 /** 669 * \fn txDataQ_UpdateQueuesBusyState 670 * \brief Update queues' busy state 671 * 672 * Update the Queues Mode to Busy according to the input TidBitMap. 673 * Each Tid that is set indicates that the related Queue is Busy. 674 * 675 * \note 676 * \param hTxDataQ - The object 677 * \param uTidBitMap - The changed TIDs busy bitmap 678 * \return void 679 * \sa 680 */ 681 static void txDataQ_UpdateQueuesBusyState (TTxDataQ *pTxDataQ, TI_UINT32 uTidBitMap) 682 { 683 TI_UINT32 uTidIdx; 684 685 /* Go over the TidBitMap and update the related queue busy state */ 686 for (uTidIdx = 0; uTidIdx < MAX_NUM_OF_802_1d_TAGS; uTidIdx++, uTidBitMap >>= 1) 687 { 688 if (uTidBitMap & 0x1) /* this Tid is busy */ 689 { 690 pTxDataQ->aQueueBusy[aTidToQueueTable[uTidIdx]] = TI_TRUE; 691 } 692 else 693 { 694 pTxDataQ->aQueueBusy[aTidToQueueTable[uTidIdx]] = TI_FALSE; 695 } 696 } 697 } 698