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