• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  ****************************************************************************/
txHwQueue_Create(TI_HANDLE hOs)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  ****************************************************************************/
txHwQueue_Destroy(TI_HANDLE hTxHwQueue)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  ****************************************************************************/
txHwQueue_Init(TI_HANDLE hTxHwQueue,TI_HANDLE hReport)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  ****************************************************************************/
txHwQueue_Config(TI_HANDLE hTxHwQueue,TTwdInitParams * pInitParams)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  ****************************************************************************/
txHwQueue_SetHwInfo(TI_HANDLE hTxHwQueue,TDmaParams * pDmaParams)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  ****************************************************************************/
txHwQueue_Restart(TI_HANDLE hTxHwQueue)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  ****************************************************************************/
txHwQueue_AllocResources(TI_HANDLE hTxHwQueue,TTxCtrlBlk * pTxCtrlBlk)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  ****************************************************************************/
txHwQueue_UpdateFreeBlocks(TTxHwQueue * pTxHwQueue,TI_UINT32 uQueueId,TI_UINT32 uFreeBlocks)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  ****************************************************************************/
txHwQueue_UpdateFreeResources(TI_HANDLE hTxHwQueue,FwStatus_t * pFwStatus)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  ****************************************************************************/
txHwQueue_CheckResources(TTxHwQueue * pTxHwQueue,TTxHwQueueInfo * pQueueInfo)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  ****************************************************************************/
txHwQueue_RegisterCb(TI_HANDLE hTxHwQueue,TI_UINT32 uCallBackId,void * fCbFunc,TI_HANDLE hCbHndl)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
txHwQueue_PrintInfo(TI_HANDLE hTxHwQueue)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