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