Home | History | Annotate | Download | only in Data_Service
      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