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 */
59const 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 */
73typedef void (* tUpdateBusyMapCb)(TI_HANDLE hCbHndl, TI_UINT32 uBackpressure);
74
75/* Per Queue HW blocks accounting data: */
76typedef 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
90typedef 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
110static void      txHwQueue_UpdateFreeBlocks (TTxHwQueue *pTxHwQueue, TI_UINT32 uQueueId, TI_UINT32 uFreeBlocks);
111static 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 ****************************************************************************/
126TI_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 ****************************************************************************/
154TI_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 ****************************************************************************/
175TI_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 ****************************************************************************/
196TI_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 ****************************************************************************/
233TI_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 ****************************************************************************/
254TI_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 ****************************************************************************/
307ETxHwQueStatus 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 ****************************************************************************/
440static 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 ****************************************************************************/
532void 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
616
617/****************************************************************************
618 *                  txHwQueue_CheckResources()
619 ****************************************************************************
620 * DESCRIPTION:
621   ============
622    Return the given queue's available blocks.
623    If no descriptors available, return 0.
624 ****************************************************************************/
625static TI_UINT32 txHwQueue_CheckResources (TTxHwQueue *pTxHwQueue, TTxHwQueueInfo *pQueueInfo)
626{
627    /* If descriptors are available: */
628    if (pTxHwQueue->uNumUsedDescriptors < NUM_TX_DESCRIPTORS)
629    {
630        /* Calculate how many buffers are available for this Queue: the total free buffers minus the buffers
631             that are reserved for other Queues (all reserved minus this Queue's reserved). */
632        return (pTxHwQueue->uNumTotalBlksFree - (pTxHwQueue->uNumTotalBlksReserved - pQueueInfo->uNumBlksReserved));
633    }
634
635    /* If no descriptors are available, return 0 (can't transmit anything). */
636    else
637    {
638        return 0;
639    }
640}
641
642
643/****************************************************************************
644 *                      txHwQueue_RegisterCb()
645 ****************************************************************************
646 * DESCRIPTION:  Register the upper driver TxHwQueue callback functions.
647 ****************************************************************************/
648void txHwQueue_RegisterCb (TI_HANDLE hTxHwQueue, TI_UINT32 uCallBackId, void *fCbFunc, TI_HANDLE hCbHndl)
649{
650    TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue;
651
652    switch (uCallBackId)
653    {
654        case TWD_INT_UPDATE_BUSY_MAP:
655            pTxHwQueue->fUpdateBusyMapCb   = (tUpdateBusyMapCb)fCbFunc;
656            pTxHwQueue->hUpdateBusyMapHndl = hCbHndl;
657            break;
658
659        default:
660            TRACE1(pTxHwQueue->hReport, REPORT_SEVERITY_ERROR, " - Illegal parameter = %d\n", uCallBackId);
661            return;
662    }
663}
664
665
666/****************************************************************************
667 *                      txHwQueue_PrintInfo()
668 ****************************************************************************
669 * DESCRIPTION: Print the Hw Queue module current information
670 ****************************************************************************/
671#ifdef TI_DBG
672void txHwQueue_PrintInfo (TI_HANDLE hTxHwQueue)
673{
674#ifdef REPORT_LOG
675    TTxHwQueue *pTxHwQueue = (TTxHwQueue *)hTxHwQueue;
676    TI_INT32 TxQid;
677
678    /* Print the Tx-HW-Queue information: */
679    WLAN_OS_REPORT(("Hw-Queues Information:\n"));
680    WLAN_OS_REPORT(("======================\n"));
681    WLAN_OS_REPORT(("Total Blocks:           %d\n", pTxHwQueue->uNumTotalBlks));
682    WLAN_OS_REPORT(("Total Free Blocks:      %d\n", pTxHwQueue->uNumTotalBlksFree));
683    WLAN_OS_REPORT(("Total Reserved Blocks:  %d\n", pTxHwQueue->uNumTotalBlksReserved));
684    WLAN_OS_REPORT(("Total Used Descriptors: %d\n", pTxHwQueue->uNumUsedDescriptors));
685    WLAN_OS_REPORT(("FwTxResultsCntr:        %d\n", pTxHwQueue->uFwTxResultsCntr));
686    WLAN_OS_REPORT(("DrvTxPacketsCntr:       %d\n", pTxHwQueue->uDrvTxPacketsCntr));
687
688    for(TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++)
689    {
690        WLAN_OS_REPORT(("Q=%d: Used=%d, Reserve=%d, Threshold=%d\n",
691            TxQid,
692            pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksUsed,
693            pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksReserved,
694            pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksThresh));
695    }
696
697    WLAN_OS_REPORT(("\n"));
698
699    for(TxQid = 0; TxQid < MAX_NUM_OF_AC; TxQid++)
700    {
701        WLAN_OS_REPORT(("Queue=%d: HostAllocCount=0x%x, FwFreeCount=0x%x, BusyBlks=%d, Busy=%d\n",
702            TxQid,
703            pTxHwQueue->aTxHwQueueInfo[TxQid].uAllocatedBlksCntr,
704            pTxHwQueue->aTxHwQueueInfo[TxQid].uFwFreedBlksCntr,
705            pTxHwQueue->aTxHwQueueInfo[TxQid].uNumBlksCausedBusy,
706            pTxHwQueue->aTxHwQueueInfo[TxQid].bQueueBusy));
707    }
708#endif
709}
710
711#endif /* TI_DBG */
712
713