1 /* 2 * txHwQueue.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 /**************************************************************************** 36 * 37 * MODULE: txHwQueue.c 38 * 39 * PURPOSE: manage the wlan hardware Tx memory blocks allocation per queue. 40 * 41 * DESCRIPTION: 42 * ============ 43 * This module is responsible for the HW Tx data-blocks and descriptors allocation. 44 * The HW Tx blocks are allocated in the driver by rough calculations without 45 * accessing the FW. 46 * They are freed according to FW counters that are provided by the FwEvent module 47 * on every FW interrupt. 48 ****************************************************************************/ 49 #define __FILE_ID__ FILE_ID_100 50 #include "osApi.h" 51 #include "report.h" 52 #include "TWDriver.h" 53 #include "txCtrlBlk_api.h" 54 #include "txHwQueue_api.h" 55 56 57 /* Translate input TID to AC */ 58 /* Note: This structure is shared with other modules */ 59 const EAcTrfcType WMEQosTagToACTable[MAX_NUM_OF_802_1d_TAGS] = 60 {QOS_AC_BE, QOS_AC_BK, QOS_AC_BK, QOS_AC_BE, QOS_AC_VI, QOS_AC_VI, QOS_AC_VO, QOS_AC_VO}; 61 62 /* 63 * Local definitions: 64 */ 65 66 /* Spare blocks written in extraMemBlks field in TxDescriptor for HW use */ 67 #define BLKS_HW_ALLOC_SPARE 2 68 69 /* Set queue's backpressure bit (indicates queue state changed from ready to busy or inversely). */ 70 #define SET_QUEUE_BACKPRESSURE(pBackpressure, uQueueId) (*pBackpressure |= (1 << uQueueId)) 71 72 /* Callback function definition for UpdateBusyMap */ 73 typedef void (* tUpdateBusyMapCb)(TI_HANDLE hCbHndl, TI_UINT32 uBackpressure); 74 75 /* Per Queue HW blocks accounting data: */ 76 typedef struct 77 { 78 TI_UINT32 uNumBlksThresh; /* Minimum HW blocks that must be reserved for this Queue. */ 79 TI_UINT32 uNumBlksUsed; /* Number of HW blocks that are currently allocated for this Queue. */ 80 TI_UINT32 uNumBlksReserved; /* Number of HW blocks currently reserved for this Queue (to guarentee the low threshold). */ 81 TI_UINT32 uAllocatedBlksCntr; /* Accumulates allocated blocks for FW freed-blocks counter coordination. */ 82 TI_UINT32 uFwFreedBlksCntr; /* Accumulated freed blocks in FW. */ 83 TI_UINT32 uNumBlksCausedBusy; /* Number of HW blocks that caused queue busy state. */ 84 TI_BOOL bQueueBusy; /* If TI_TRUE, this queue is currently stopped. */ 85 TI_UINT16 uPercentOfBlkLowThresh; /* Configured percentage of blocks to use as the queue's low allocation threshold */ 86 TI_UINT16 uPercentOfBlkHighThresh; /* Configured percentage of blocks to use as the queue's high allocation threshold */ 87 88 } TTxHwQueueInfo; 89 90 typedef struct 91 { 92 TI_HANDLE hOs; 93 TI_HANDLE hReport; 94 95 tUpdateBusyMapCb fUpdateBusyMapCb; /* The upper layers UpdateBusyMap callback */ 96 TI_HANDLE hUpdateBusyMapHndl;/* The handle for the fUpdateBusyMapCb */ 97 98 TI_UINT32 uNumTotalBlks; /* The total number of Tx blocks */ 99 TI_UINT32 uNumTotalBlksFree; /* Total number of free HW blocks */ 100 TI_UINT32 uNumTotalBlksReserved; /* Total number of free but reserved HW blocks */ 101 TI_UINT32 uNumUsedDescriptors; /* Total number of packets in the FW. */ 102 TI_UINT8 uFwTxResultsCntr; /* Accumulated freed descriptors in FW. */ 103 TI_UINT8 uDrvTxPacketsCntr; /* Accumulated allocated descriptors in driver. */ 104 105 TTxHwQueueInfo aTxHwQueueInfo[MAX_NUM_OF_AC]; /* The per queue variables */ 106 107 } TTxHwQueue; 108 109 110 static void txHwQueue_UpdateFreeBlocks (TTxHwQueue *pTxHwQueue, TI_UINT32 uQueueId, TI_UINT32 uFreeBlocks); 111 static TI_UINT32 txHwQueue_CheckResources (TTxHwQueue *pTxHwQueue, TTxHwQueueInfo *pQueueInfo); 112 113 114 115 /**************************************************************************** 116 * txHwQueue_Create() 117 **************************************************************************** 118 * DESCRIPTION: Create the Tx buffers pool object 119 * 120 * INPUTS: None 121 * 122 * OUTPUT: None 123 * 124 * RETURNS: The Created object 125 ****************************************************************************/ 126 TI_HANDLE txHwQueue_Create (TI_HANDLE hOs) 127 { 128 TTxHwQueue *pTxHwQueue; 129 130 pTxHwQueue = os_memoryAlloc(hOs, sizeof(TTxHwQueue)); 131 if (pTxHwQueue == NULL) 132 { 133 return NULL; 134 } 135 136 os_memoryZero(hOs, pTxHwQueue, sizeof(TTxHwQueue)); 137 138 pTxHwQueue->hOs = hOs; 139 140 return (TI_HANDLE)pTxHwQueue; 141 } 142 143 /**************************************************************************** 144 * txHwQueue_Destroy() 145 **************************************************************************** 146 * DESCRIPTION: Destroy the Tx buffers pool object 147 * 148 * INPUTS: hTxHwQueue - The object to free 149 * 150 * OUTPUT: None 151 * 152 * RETURNS: TI_OK or TI_NOK 153 ****************************************************************************/ 154 TI_STATUS txHwQueue_Destroy (TI_HANDLE hTxHwQueue) 155 { 156 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 157 158 if (pTxHwQueue) 159 { 160 os_memoryFree(pTxHwQueue->hOs, pTxHwQueue, sizeof(TTxHwQueue)); 161 } 162 return TI_OK; 163 } 164 165 166 167 168 /**************************************************************************** 169 * txHwQueue_Init() 170 **************************************************************************** 171 172 DESCRIPTION: Initialize module handles. 173 174 ****************************************************************************/ 175 TI_STATUS txHwQueue_Init (TI_HANDLE hTxHwQueue, TI_HANDLE hReport) 176 { 177 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 178 179 pTxHwQueue->hReport = hReport; 180 181 return TI_OK; 182 } 183 184 185 /**************************************************************************** 186 * txHwQueue_Config() 187 **************************************************************************** 188 * DESCRIPTION: Configure the Tx buffers pool object 189 * 190 * INPUTS: None 191 * 192 * OUTPUT: None 193 * 194 * RETURNS: 195 ****************************************************************************/ 196 TI_STATUS txHwQueue_Config (TI_HANDLE hTxHwQueue, TTwdInitParams *pInitParams) 197 { 198 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 199 TI_UINT32 TxQid; 200 201 /* Configure queue parameters to Tx-HW queue module */ 202 for (TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) 203 { 204 pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksThresh = pInitParams->tGeneral.TxBlocksThresholdPerAc[TxQid]; 205 } 206 207 return TI_OK; 208 } 209 210 211 212 /**************************************************************************** 213 * txHwQueue_SetHwInfo() 214 **************************************************************************** 215 216 DESCRIPTION: 217 218 Called after the HW configuration in the driver init or recovery process. 219 Configure Tx HW information, including Tx-HW-blocks number, and per queue 220 Tx-descriptors number. Than, restart the module variables. 221 222 Two thresholds are defined per queue: 223 a) TxBlocksLowPercentPerQueue[queue] - The lower threshold is the minimal number of 224 Tx blocks guaranteed for each queue. 225 The sum of all low thresholds should be less than 100%. 226 b) TxBlocksHighPercentPerQueue[queue] - The higher threshold is the maximal number of 227 Tx blocks that may be allocated to the queue. 228 The extra blocks above the low threshold can be allocated when needed only 229 if they are currently available and are not needed in order to guarantee 230 the other queues low threshold. 231 The sum of all high thresholds should be more than 100%. 232 ****************************************************************************/ 233 TI_STATUS txHwQueue_SetHwInfo (TI_HANDLE hTxHwQueue, TDmaParams *pDmaParams) 234 { 235 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 236 237 pTxHwQueue->uNumTotalBlks = pDmaParams->NumTxBlocks - 1; /* One block must be always free for FW use. */ 238 239 /* Restart the module variables. */ 240 txHwQueue_Restart (hTxHwQueue); 241 242 return TI_OK; 243 } 244 245 246 /**************************************************************************** 247 * txHwQueue_Restart() 248 **************************************************************************** 249 DESCRIPTION: 250 ============ 251 Called after the HW configuration in the driver init or recovery process. 252 Restarts the Tx-HW-Queue module. 253 ****************************************************************************/ 254 TI_STATUS txHwQueue_Restart (TI_HANDLE hTxHwQueue) 255 { 256 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 257 TTxHwQueueInfo *pQueueInfo; 258 TI_UINT32 TxQid; 259 260 261 /* 262 * All blocks are free at restart. 263 * Note that free means all blocks that are currently not in use, while reserved are 264 * a part of the free blocks that are the summary of all queues reserved blocks. 265 * Each queue may take from the reserved part only up to its own reservation (according to 266 * its low threshold). 267 */ 268 pTxHwQueue->uNumTotalBlksFree = pTxHwQueue->uNumTotalBlks; 269 pTxHwQueue->uNumTotalBlksReserved = 0; 270 pTxHwQueue->uNumUsedDescriptors = 0; 271 pTxHwQueue->uFwTxResultsCntr = 0; 272 pTxHwQueue->uDrvTxPacketsCntr = 0; 273 274 for (TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) 275 { 276 pQueueInfo = &pTxHwQueue->aTxHwQueueInfo[TxQid]; 277 278 pQueueInfo->uNumBlksUsed = 0; 279 pQueueInfo->uAllocatedBlksCntr = 0; 280 pQueueInfo->uFwFreedBlksCntr = 0; 281 pQueueInfo->uNumBlksCausedBusy = 0; 282 pQueueInfo->bQueueBusy = TI_FALSE; 283 284 /* Since no blocks are used yet, reserved blocks number equals to the low threshold. */ 285 pQueueInfo->uNumBlksReserved = pQueueInfo->uNumBlksThresh; 286 287 /* Accumulate total reserved blocks. */ 288 pTxHwQueue->uNumTotalBlksReserved += pQueueInfo->uNumBlksReserved; 289 } 290 291 return TI_OK; 292 } 293 294 295 /**************************************************************************** 296 * txHwQueue_AllocResources() 297 **************************************************************************** 298 * DESCRIPTION: 299 ============ 300 1. Estimate required HW-blocks number. 301 2. If the required blocks are not available or no free descriptor, 302 return STOP_CURRENT (to stop current queue and requeue the packet). 303 3. Resources are available so update allocated blocks and descriptors counters. 304 4. If no resources for another similar packet, return STOP_NEXT (to stop current queue). 305 Else, return SUCCESS 306 ****************************************************************************/ 307 ETxHwQueStatus txHwQueue_AllocResources (TI_HANDLE hTxHwQueue, TTxCtrlBlk *pTxCtrlBlk) 308 { 309 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 310 TI_UINT32 uNumBlksToAlloc; /* The number of blocks required for the current packet. */ 311 TI_UINT32 uExcludedLength; /* The data length not included in the rough blocks calculation */ 312 TI_UINT32 uAvailableBlks; /* Max blocks that are currently available for this queue. */ 313 TI_UINT32 uReservedBlks; /* How many blocks are reserved for this queue before this allocation. */ 314 TI_UINT32 uQueueId = WMEQosTagToACTable[pTxCtrlBlk->tTxDescriptor.tid]; 315 TTxHwQueueInfo *pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); 316 317 318 /***********************************************************************/ 319 /* Calculate packet required HW blocks. */ 320 /***********************************************************************/ 321 322 /* Divide length by 256 instead of 252 (block size) to save CPU */ 323 uNumBlksToAlloc = ( pTxCtrlBlk->tTxDescriptor.length + 20 ) >> 8; 324 325 /* The length not yet included in the uNumBlksToAlloc is the sum of: 326 1) 4 bytes per block as a result of using 256 instead of 252 block size. 327 2) The remainder of the division by 256. 328 3) Overhead due to header translation, security and LLC header (subtracting ethernet header). 329 */ 330 uExcludedLength = (uNumBlksToAlloc << 2) + ((pTxCtrlBlk->tTxDescriptor.length + 20) & 0xFF) + MAX_HEADER_SIZE - 14; 331 332 /* Add 1 or 2 blocks for the excluded length, according to its size */ 333 uNumBlksToAlloc += (uExcludedLength > 252) ? 2 : 1; 334 335 /* Add extra blocks needed in case of fragmentation */ 336 uNumBlksToAlloc += BLKS_HW_ALLOC_SPARE; 337 338 /***********************************************************************/ 339 /* Check if the required resources are available */ 340 /***********************************************************************/ 341 342 /* Find max available blocks for this queue (0 could indicate no descriptors). */ 343 uAvailableBlks = txHwQueue_CheckResources (pTxHwQueue, pQueueInfo); 344 345 /* If we need more blocks than available, return STOP_CURRENT (stop current queue and requeue packet). */ 346 if (uNumBlksToAlloc > uAvailableBlks) 347 { 348 TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": No resources, Queue=%d, ReqBlks=%d, FreeBlks=%d, UsedBlks=%d, AvailBlks=%d, UsedPkts=%d\n", uQueueId, uNumBlksToAlloc, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, uAvailableBlks, pTxHwQueue->uNumUsedDescriptors); 349 pQueueInfo->uNumBlksCausedBusy = uNumBlksToAlloc; 350 pQueueInfo->bQueueBusy = TI_TRUE; 351 352 return TX_HW_QUE_STATUS_STOP_CURRENT; /**** Exit! (we should stop queue and requeue packet) ****/ 353 } 354 355 /***********************************************************************/ 356 /* Allocate required resources */ 357 /***********************************************************************/ 358 359 /* Update blocks numbers in Tx descriptor */ 360 pTxCtrlBlk->tTxDescriptor.extraMemBlks = BLKS_HW_ALLOC_SPARE; 361 pTxCtrlBlk->tTxDescriptor.totalMemBlks = uNumBlksToAlloc; 362 363 /* Update packet allocation info: */ 364 pTxHwQueue->uNumUsedDescriptors++; /* Update number of packets in FW (for descriptors allocation check). */ 365 pTxHwQueue->uDrvTxPacketsCntr++; 366 pQueueInfo->uAllocatedBlksCntr += uNumBlksToAlloc; /* For FW counter coordination. */ 367 uReservedBlks = pQueueInfo->uNumBlksReserved; 368 369 /* If we are currently using less than the low threshold (i.e. we have some reserved blocks), 370 blocks allocation should reduce the reserved blocks number as follows: 371 */ 372 if (uReservedBlks) 373 { 374 375 /* If adding the allocated blocks to the used blocks will pass the low-threshold, 376 only the part up to the low-threshold is subtracted from the reserved blocks. 377 This is because blocks are reserved for the Queue only up to its low-threshold. 378 379 0 old used low new used high 380 |######| | | | 381 |######| | | | 382 <------------ allocated -----------> 383 <----- old reserved ----> 384 new reserved = 0 (we passed the low threshold) 385 */ 386 if (uNumBlksToAlloc > uReservedBlks) 387 { 388 pQueueInfo->uNumBlksReserved = 0; 389 pTxHwQueue->uNumTotalBlksReserved -= uReservedBlks; /* reduce change from total reserved.*/ 390 } 391 392 393 /* Else, if allocating less than reserved, 394 the allocated blocks are subtracted from the reserved blocks: 395 396 0 old used new used low high 397 |######| | | | 398 |######| | | | 399 <- allocated -> 400 <--------- old reserved ----------> 401 <-- new reserved --> 402 */ 403 else 404 { 405 pQueueInfo->uNumBlksReserved -= uNumBlksToAlloc; 406 pTxHwQueue->uNumTotalBlksReserved -= uNumBlksToAlloc; /* reduce change from total reserved.*/ 407 } 408 } 409 410 411 /* Update total free blocks and Queue used blocks with the allocated blocks number. */ 412 pTxHwQueue->uNumTotalBlksFree -= uNumBlksToAlloc; 413 pQueueInfo->uNumBlksUsed += uNumBlksToAlloc; 414 415 TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": SUCCESS, Queue=%d, Req-blks=%d , Free=%d, Used=%d, Reserved=%d, Accumulated=%d\n", uQueueId, uNumBlksToAlloc, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, pQueueInfo->uNumBlksReserved, pQueueInfo->uAllocatedBlksCntr); 416 417 /* If no resources for another similar packet, return STOP_NEXT (to stop current queue). */ 418 /* Note: Current packet transmission is continued */ 419 if ( (uNumBlksToAlloc << 1) > uAvailableBlks ) 420 { 421 TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": No resources for next pkt, Queue=%d, ReqBlks=%d, FreeBlks=%d, UsedBlks=%d, AvailBlks=%d, UsedPkts=%d\n", uQueueId, uNumBlksToAlloc, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, uAvailableBlks, pTxHwQueue->uNumUsedDescriptors); 422 pQueueInfo->uNumBlksCausedBusy = uNumBlksToAlloc; 423 pQueueInfo->bQueueBusy = TI_TRUE; 424 return TX_HW_QUE_STATUS_STOP_NEXT; 425 } 426 427 /* Return SUCCESS (resources are available). */ 428 return TX_HW_QUE_STATUS_SUCCESS; 429 } 430 431 432 /**************************************************************************** 433 * txHwQueue_UpdateFreeBlocks() 434 **************************************************************************** 435 * DESCRIPTION: 436 =========== 437 This function is called per queue after reading the freed blocks counters from the FwStatus. 438 It updates the queue's blocks status according to the freed blocks. 439 ****************************************************************************/ 440 static void txHwQueue_UpdateFreeBlocks (TTxHwQueue *pTxHwQueue, TI_UINT32 uQueueId, TI_UINT32 uFreeBlocks) 441 { 442 TTxHwQueueInfo *pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); 443 TI_UINT32 lowThreshold; /* Minimum blocks that are guaranteed for this Queue. */ 444 TI_UINT32 newUsedBlks; /* Blocks that are used by this Queue after updating free blocks. */ 445 TI_UINT32 newReserved; /* How many blocks are reserved to this Queue after freeing. */ 446 TI_UINT32 numBlksToFree; /* The number of blocks freed in the current queue. */ 447 448 /* If the FW free blocks counter didn't change, exit */ 449 uFreeBlocks = ENDIAN_HANDLE_LONG(uFreeBlocks); 450 if (uFreeBlocks == pQueueInfo->uFwFreedBlksCntr) 451 { 452 return; 453 } 454 455 pQueueInfo->uFwFreedBlksCntr = uFreeBlocks; 456 457 /* The uFreeBlocks is the accumulated number of blocks freed by the FW for the uQueueId. 458 * Subtracting it from the accumulated number of blocks allocated by the driver should 459 * give the current number of used blocks in this queue. 460 * Since the difference is always a small positive number, a simple subtraction should work 461 * also for wrap around. 462 */ 463 newUsedBlks = pQueueInfo->uAllocatedBlksCntr - uFreeBlocks; 464 465 numBlksToFree = pQueueInfo->uNumBlksUsed - newUsedBlks; 466 467 #ifdef TI_DBG /* Sanity check: make sure we don't free more than is allocated. */ 468 if (numBlksToFree > pQueueInfo->uNumBlksUsed) 469 { 470 TRACE5(pTxHwQueue->hReport, REPORT_SEVERITY_ERROR, ": Try to free more blks than used: Queue %d, ToFree %d, Used %d, HostAlloc=0x%x, FwFree=0x%x\n", uQueueId, numBlksToFree, pQueueInfo->uNumBlksUsed, pQueueInfo->uAllocatedBlksCntr, uFreeBlocks); 471 } 472 #endif 473 474 /* Update total free blocks and Queue used blocks with the freed blocks number. */ 475 pTxHwQueue->uNumTotalBlksFree += numBlksToFree; 476 pQueueInfo->uNumBlksUsed = newUsedBlks; 477 478 lowThreshold = pQueueInfo->uNumBlksThresh; 479 480 /* If after freeing the blocks we are using less than the low threshold, 481 update total reserved blocks number as follows: 482 (note: if we are above the low threshold after freeing the blocks we still have no reservation.) 483 */ 484 if (newUsedBlks < lowThreshold) 485 { 486 newReserved = lowThreshold - newUsedBlks; 487 pQueueInfo->uNumBlksReserved = newReserved; 488 489 490 /* If freeing the blocks reduces the used blocks from above to below the low-threshold, 491 only the part from the low-threshold to the new used number is added to the 492 reserved blocks (because blocks are reserved for the Queue only up to its low-threshold): 493 494 0 new used low old used high 495 |###########|####################|################| | 496 |###########|####################|################| | 497 <-------------- freed --------------> 498 <-- new reserved --> 499 old reserved = 0 500 */ 501 if (numBlksToFree > newReserved) 502 pTxHwQueue->uNumTotalBlksReserved += newReserved; /* Add change to total reserved.*/ 503 504 505 /* Else, if we were under the low-threshold before freeing these blocks, 506 all freed blocks are added to the reserved blocks: 507 508 0 new used old used low high 509 |################|#################| | | 510 |################|#################| | | 511 <---- freed ----> 512 <- old reserved -> 513 <---------- new reserved ----------> 514 */ 515 else 516 pTxHwQueue->uNumTotalBlksReserved += numBlksToFree; /* Add change to total reserved.*/ 517 } 518 519 TRACE5(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": Queue %d, ToFree %d, Used %d, HostAlloc=0x%x, FwFree=0x%x\n", uQueueId, numBlksToFree, pQueueInfo->uNumBlksUsed, pQueueInfo->uAllocatedBlksCntr, uFreeBlocks); 520 } 521 522 523 /**************************************************************************** 524 * txHwQueue_UpdateFreeResources() 525 **************************************************************************** 526 * DESCRIPTION: 527 =========== 528 Called by FwEvent upon Data interrupt to update freed HW-Queue resources as follows: 529 1) For all queues, update blocks and descriptors numbers according to FwStatus information. 530 2) For each busy queue, if now available indicate it in the backpressure bitmap. 531 ****************************************************************************/ 532 ETxnStatus txHwQueue_UpdateFreeResources (TI_HANDLE hTxHwQueue, FwStatus_t *pFwStatus) 533 { 534 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 535 TTxHwQueueInfo *pQueueInfo; 536 TI_UINT32 uQueueId; 537 TI_UINT32 uAvailableBlks; /* Max blocks available for current queue. */ 538 TI_UINT32 uNewNumUsedDescriptors; 539 TI_UINT32 uBackpressure = 0; 540 TI_UINT32 *pFreeBlocks = (TI_UINT32 *)pFwStatus->txReleasedBlks; 541 TI_UINT32 uTempFwCounters; 542 FwStatCntrs_t *pFwStatusCounters; 543 544 /* 545 * If TxResults counter changed in FwStatus, update descriptors number according to information 546 */ 547 uTempFwCounters = (ENDIAN_HANDLE_LONG(pFwStatus->counters)); 548 pFwStatusCounters = (FwStatCntrs_t *)&uTempFwCounters; 549 if (pFwStatusCounters->txResultsCntr != pTxHwQueue->uFwTxResultsCntr) 550 { 551 pTxHwQueue->uFwTxResultsCntr = pFwStatusCounters->txResultsCntr; 552 553 /* Calculate new number of used descriptors (the else is for wrap around case) */ 554 if (pTxHwQueue->uFwTxResultsCntr <= pTxHwQueue->uDrvTxPacketsCntr) 555 { 556 uNewNumUsedDescriptors = (TI_UINT32)(pTxHwQueue->uDrvTxPacketsCntr - pTxHwQueue->uFwTxResultsCntr); 557 } 558 else 559 { 560 uNewNumUsedDescriptors = 0x100 - (TI_UINT32)(pTxHwQueue->uFwTxResultsCntr - pTxHwQueue->uDrvTxPacketsCntr); 561 } 562 563 #ifdef TI_DBG /* Sanity check: make sure we don't free more descriptors than allocated. */ 564 if (uNewNumUsedDescriptors >= pTxHwQueue->uNumUsedDescriptors) 565 { 566 TRACE2(pTxHwQueue->hReport, REPORT_SEVERITY_ERROR, ": Used descriptors number should decrease: UsedDesc %d, NewUsedDesc %d\n", pTxHwQueue->uNumUsedDescriptors, uNewNumUsedDescriptors); 567 } 568 #endif 569 570 /* Update number of packets left in FW (for descriptors allocation check). */ 571 pTxHwQueue->uNumUsedDescriptors = uNewNumUsedDescriptors; 572 } 573 574 /* 575 * For all queues, update blocks numbers according to FwStatus information 576 */ 577 for (uQueueId = 0; uQueueId < MAX_NUM_OF_AC; uQueueId++) 578 { 579 pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); 580 581 /* Update per queue number of used, free and reserved blocks. */ 582 txHwQueue_UpdateFreeBlocks (pTxHwQueue, uQueueId, pFreeBlocks[uQueueId]); 583 } 584 585 /* 586 * For each busy queue, if now available indicate it in the backpressure bitmap 587 */ 588 for (uQueueId = 0; uQueueId < MAX_NUM_OF_AC; uQueueId++) 589 { 590 pQueueInfo = &(pTxHwQueue->aTxHwQueueInfo[uQueueId]); 591 592 /* If the queue was stopped */ 593 if (pQueueInfo->bQueueBusy) 594 { 595 /* Find max available blocks for this queue (0 could indicate no descriptors). */ 596 uAvailableBlks = txHwQueue_CheckResources (pTxHwQueue, pQueueInfo); 597 598 /* If the required blocks and a descriptor are available, 599 set the queue's backpressure bit to indicate NOT-busy! */ 600 if (pQueueInfo->uNumBlksCausedBusy <= uAvailableBlks) 601 { 602 TRACE6(pTxHwQueue->hReport, REPORT_SEVERITY_INFORMATION, ": Queue Available, Queue=%d, ReqBlks=%d, FreeBlks=%d, UsedBlks=%d, AvailBlks=%d, UsedPkts=%d\n", uQueueId, pQueueInfo->uNumBlksCausedBusy, pTxHwQueue->uNumTotalBlksFree, pQueueInfo->uNumBlksUsed, uAvailableBlks, pTxHwQueue->uNumUsedDescriptors); 603 SET_QUEUE_BACKPRESSURE(&uBackpressure, uQueueId); /* Start queue. */ 604 pQueueInfo->bQueueBusy = TI_FALSE; 605 } 606 } 607 } 608 609 /* If released queues map is not 0, send it to the upper layers (if CB available) */ 610 if ((uBackpressure > 0) && (pTxHwQueue->fUpdateBusyMapCb != NULL)) 611 { 612 pTxHwQueue->fUpdateBusyMapCb (pTxHwQueue->hUpdateBusyMapHndl, uBackpressure); 613 } 614 615 return TXN_STATUS_COMPLETE; 616 } 617 618 619 /**************************************************************************** 620 * txHwQueue_CheckResources() 621 **************************************************************************** 622 * DESCRIPTION: 623 ============ 624 Return the given queue's available blocks. 625 If no descriptors available, return 0. 626 ****************************************************************************/ 627 static TI_UINT32 txHwQueue_CheckResources (TTxHwQueue *pTxHwQueue, TTxHwQueueInfo *pQueueInfo) 628 { 629 /* If descriptors are available: */ 630 if (pTxHwQueue->uNumUsedDescriptors < NUM_TX_DESCRIPTORS) 631 { 632 /* Calculate how many buffers are available for this Queue: the total free buffers minus the buffers 633 that are reserved for other Queues (all reserved minus this Queue's reserved). */ 634 return (pTxHwQueue->uNumTotalBlksFree - (pTxHwQueue->uNumTotalBlksReserved - pQueueInfo->uNumBlksReserved)); 635 } 636 637 /* If no descriptors are available, return 0 (can't transmit anything). */ 638 else 639 { 640 return 0; 641 } 642 } 643 644 645 /**************************************************************************** 646 * txHwQueue_RegisterCb() 647 **************************************************************************** 648 * DESCRIPTION: Register the upper driver TxHwQueue callback functions. 649 ****************************************************************************/ 650 void txHwQueue_RegisterCb (TI_HANDLE hTxHwQueue, TI_UINT32 uCallBackId, void *fCbFunc, TI_HANDLE hCbHndl) 651 { 652 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 653 654 switch (uCallBackId) 655 { 656 case TWD_INT_UPDATE_BUSY_MAP: 657 pTxHwQueue->fUpdateBusyMapCb = (tUpdateBusyMapCb)fCbFunc; 658 pTxHwQueue->hUpdateBusyMapHndl = hCbHndl; 659 break; 660 661 default: 662 TRACE1(pTxHwQueue->hReport, REPORT_SEVERITY_ERROR, " - Illegal parameter = %d\n", uCallBackId); 663 return; 664 } 665 } 666 667 668 /**************************************************************************** 669 * txHwQueue_PrintInfo() 670 **************************************************************************** 671 * DESCRIPTION: Print the Hw Queue module current information 672 ****************************************************************************/ 673 #ifdef TI_DBG 674 void txHwQueue_PrintInfo (TI_HANDLE hTxHwQueue) 675 { 676 #ifdef REPORT_LOG 677 TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue; 678 TI_INT32 TxQid; 679 680 /* Print the Tx-HW-Queue information: */ 681 WLAN_OS_REPORT(("Hw-Queues Information:\n")); 682 WLAN_OS_REPORT(("======================\n")); 683 WLAN_OS_REPORT(("Total Blocks: %d\n", pTxHwQueue->uNumTotalBlks)); 684 WLAN_OS_REPORT(("Total Free Blocks: %d\n", pTxHwQueue->uNumTotalBlksFree)); 685 WLAN_OS_REPORT(("Total Reserved Blocks: %d\n", pTxHwQueue->uNumTotalBlksReserved)); 686 WLAN_OS_REPORT(("Total Used Descriptors: %d\n", pTxHwQueue->uNumUsedDescriptors)); 687 WLAN_OS_REPORT(("FwTxResultsCntr: %d\n", pTxHwQueue->uFwTxResultsCntr)); 688 WLAN_OS_REPORT(("DrvTxPacketsCntr: %d\n", pTxHwQueue->uDrvTxPacketsCntr)); 689 690 for(TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) 691 { 692 WLAN_OS_REPORT(("Q=%d: Used=%d, Reserve=%d, Threshold=%d\n", 693 TxQid, 694 pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksUsed, 695 pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksReserved, 696 pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksThresh)); 697 } 698 699 WLAN_OS_REPORT(("\n")); 700 701 for(TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++) 702 { 703 WLAN_OS_REPORT(("Queue=%d: HostAllocCount=0x%x, FwFreeCount=0x%x, BusyBlks=%d, Busy=%d\n", 704 TxQid, 705 pTxHwQueue->aTxHwQueueInfo[TxQid].uAllocatedBlksCntr, 706 pTxHwQueue->aTxHwQueueInfo[TxQid].uFwFreedBlksCntr, 707 pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksCausedBusy, 708 pTxHwQueue->aTxHwQueueInfo[TxQid].bQueueBusy)); 709 } 710 #endif 711 } 712 713 #endif /* TI_DBG */ 714 715