source: svn/trunk/newcon3bcm2_21bu/magnum/portinginterface/dma/7552/bdma_queue.c

Last change on this file was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 42.7 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2003-2011, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: bdma_queue.c $
11 * $brcm_Revision: Hydra_Software_Devel/12 $
12 * $brcm_Date: 3/21/11 6:39p $
13 *
14 * Module Description:
15 *
16 *
17 * Revision History:
18 * $brcm_Log: /magnum/portinginterface/dma/7400/bdma_queue.c $
19 *
20 * Hydra_Software_Devel/12   3/21/11 6:39p vanessah
21 * SW7420-1431: support oflarge DMA descriptor list subset
22 *
23 * Hydra_Software_Devel/11   3/17/11 11:39a vanessah
24 * SW7346-98: bad hw descriptor issue
25 *
26 * Hydra_Software_Devel/10   9/13/10 1:46p vanessah
27 * SW7400-2835:  coverity expression issue.
28 *
29 * Hydra_Software_Devel/9   8/17/10 12:17p vanessah
30 * SW7335-791:  After customer verification, merged into main
31 *
32 * Hydra_Software_Devel/SW7335-791/1   8/4/10 10:19p vanessah
33 * SW7335-791:  DMA engine hangs when continuous descriptors using
34 * different scram modes
35 *
36 * Hydra_Software_Devel/8   5/26/10 7:10p albertl
37 * SW7405-4402: Initialized ulHwActDesc and ulScratchReg to 0 to address
38 * potential coverity issue.
39 *
40 * Hydra_Software_Devel/7   6/9/09 4:18p syang
41 * PR 55794: fixed coverity error
42 *
43 * Hydra_Software_Devel/6   8/20/08 4:09p syang
44 * PR 45212: clean up #define
45 *
46 * Hydra_Software_Devel/5   8/20/08 2:07p syang
47 * PR 45212: add msg print for debug
48 *
49 * Hydra_Software_Devel/4   7/31/08 10:52a syang
50 * PR 34606:  cleanup ASSERT
51 *
52 * Hydra_Software_Devel/3   7/30/08 3:52p syang
53 * PR 42394: avoid tran dyn-linking to itself in bSgOpen case
54 *
55 * Hydra_Software_Devel/2   7/30/08 2:29p syang
56 * PR 44358: avoid pLastEntryInHw->ulDescPhysAddr as pLastEntryInHw==NULL
57 *
58 * Hydra_Software_Devel/30   5/28/08 5:14p syang
59 * PR 34606:  handle the dyn link failure when AUTO_PEND is supported and
60 * LAST bit in desc is not cleared
61 *
62 * Hydra_Software_Devel/29   5/28/08 12:51p syang
63 * PR 34606:  clean up assert code
64 *
65 * Hydra_Software_Devel/28   5/28/08 12:43p syang
66 * PR 34606: clean up
67 *
68 * Hydra_Software_Devel/27   5/28/08 12:33p syang
69 * PR 34606: clean LAST bit during dyn link even if AUTO_PEND supported;
70 * clean up
71 *
72 * Hydra_Software_Devel/26   5/19/08 1:58p syang
73 * PR 34606:  clean up
74 *
75 * Hydra_Software_Devel/25   5/19/08 11:48a syang
76 * PR 34606:  add validation for HW reg reading
77 *
78 * Hydra_Software_Devel/24   3/4/08 11:47a rpan
79 * PR40210: Silence a Klockwork warning.
80 *
81 * Hydra_Software_Devel/23   2/27/08 10:57a rpan
82 * PR39458: Silenced a compile warning.
83 *
84 * Hydra_Software_Devel/22   2/6/08 10:17a jrubio
85 * PR39363: fixing warnings in new toolchain
86 *
87 * Hydra_Software_Devel/21   12/14/07 11:19a syang
88 * PR 34606: simplify ProcInProgressStatus()
89 *
90 * Hydra_Software_Devel/20   12/7/07 6:38p syang
91 * PR 34606: move SetCrypto to Tran level from Engine level for better
92 * sharing by threads of the same progress
93 *
94 * Hydra_Software_Devel/19   12/7/07 4:08p syang
95 * PR 34606: rewrite more than half of code to support hw sharing for
96 * kernel and user-mode sides
97 *
98 * Hydra_Software_Devel/18   10/15/07 3:39p syang
99 * PR 35947: add "_isr" to call back func name
100 *
101 * Hydra_Software_Devel/17   10/15/07 11:59a syang
102 * PR 35048: coverity (FORWARD_NULL) fix
103 *
104 * Hydra_Software_Devel/16   7/31/07 10:42a syang
105 * PR 33364: don't do corrupt check by default (for performance)
106 *
107 * Hydra_Software_Devel/15   3/22/07 2:19p syang
108 * PR 28173: add more msg
109 *
110 * Hydra_Software_Devel/14   3/21/07 12:47p syang
111 * PR 28173: dyn link works now after fixing next_desc shift and status
112 * proc  tran loop break. fixed cur hw desc left shift
113 *
114 * Hydra_Software_Devel/13   3/20/07 1:26p syang
115 * PR 28171: clean up
116 *
117 * Hydra_Software_Devel/12   3/16/07 12:47p syang
118 * PR 28173: add dynamic link support (not turn on yet)
119 *
120 * Hydra_Software_Devel/10   1/25/07 12:32p syang
121 * PR 27322: replace wrong assert of bSeeLastIssued with msg
122 *
123 * Hydra_Software_Devel/9   3/23/06 5:07p syang
124 * PR 20398:  desc has to be 32-bytes alligned for 7400 and 7401
125 *
126 * Hydra_Software_Devel/8   2/4/04 3:02p syang
127 * PR 9608: 1). added init for hMemDma / hPciDma of Channel, hDma of
128 * MemDma / PciDma and hChannel of Queue; 2). split CallBackFunc type def
129 * to mem and pci versions; 3). fixed typo in TranHandle def; 4).leave
130 * critical section before calling BINT func; 5). fixed a bug with
131 * nextDesc in Desc info setting; 6). use wake to start dma as in sleep
132 * mode; 7). corrected typo in the asserts of Queue_CreateTran.
133 *
134 * Hydra_Software_Devel/7   10/23/03 11:07a syang
135 * first time checking after resolving comipling errors
136 *
137 * Hydra_Software_Devel/6   10/17/03 4:15p syang
138 * updated to use TranHandle (rather than TranId).
139 *
140 * Hydra_Software_Devel/5   10/10/03 4:01p syang
141 * Simplified index wrap around implementation, added ProcCancelCall
142 *
143 * Hydra_Software_Devel/4   9/30/03 2:43p syang
144 * added assert, changed to use queue handle, added
145 * BDMA_P_Queue_ProcStartCall
146 *
147 * Hydra_Software_Devel/3   9/25/03 6:33p syang
148 * split out bdma_queue.h from bdma_priv.h
149 *
150 * Hydra_Software_Devel/2   9/25/03 5:18p syang
151 * init version, from scratch
152 *
153 ***************************************************************************/
154
155#include "bdma_queue.h"
156#include "bkni.h"
157
158BDBG_MODULE(BDMA);
159
160
161/***************************************************************************
162 *
163 * Debug functions
164 *
165 *************************************************************************/
166
167#define BDMA_P_QUEUE_WRAP_INDEX(index) \
168        ((index < pQueue->CmnSettings.ulTotalNumBlocks)? index: 0)
169
170#if ((BDBG_DEBUG_BUILD) && (BDMA_P_CHECK_CORRUPT))
171#define BDMA_P_QUEUE_ASSERT_UNCORRUPT(pQueue) \
172        BDMA_P_Queue_CheckQCorruption_isr(pQueue)
173#else
174#define BDMA_P_QUEUE_ASSERT_UNCORRUPT(pQueue)
175#endif
176
177#if ((BDBG_DEBUG_BUILD) && (BDMA_P_CHECK_NEXT_DESC))
178#define BDMA_P_QUEUE_CHECK_NEXT_DESC(pQueue) \
179        BDMA_P_Queue_CheckNextDescInHw_isr(pQueue)
180#else
181#define BDMA_P_QUEUE_CHECK_NEXT_DESC(pQueue)
182#endif
183
184/*--------------------------------------------------------------------------
185 * {private}
186 * BDMA_P_Queue_CheckQCorruption_isr
187 *
188 * To be called to assert that the queue is not corrupted.
189 * It should be called only if we are debugging or if some fetal error happened
190*/
191static void BDMA_P_Queue_CheckQCorruption_isr
192        ( BDMA_P_QueueContext *    pQueue )
193{
194        uint32_t ulLastAssignedId;
195        uint32_t ulTranEntry;    /* Entry index of the Tran's 1st Entry */
196        uint32_t ulBlockEntry;   /* Entry index of the block */
197        BDMA_P_QueueEntry *  pTranEntry;  /* Entry ptr of the Tran's 1st Entry */
198        BDMA_P_QueueEntry *  pBlockEntry; /* Entry ptr of the block */
199        BDMA_P_QueueEntry *  pHeadTranInHw;
200        BDMA_P_QueueEntry *  pTailTranInHw;
201        uint32_t ulNumBlocks, ulNumQueueEntries, ulMaxNumBlkPerTran;
202        uint32_t ulBlockEntryLimit;
203        bool  bSee1stUnFinished = false;
204        bool  bSeeLastIssued = false;
205        bool  bSeeLastAssigned = false;
206       
207        BDBG_ASSERT( NULL != pQueue );
208       
209        ulLastAssignedId = pQueue->ulIndx_LastEntryAssigned;
210        ulNumQueueEntries = pQueue->CmnSettings.ulTotalNumBlocks;
211        ulMaxNumBlkPerTran = pQueue->CmnSettings.ulMaxNumBlocksPerTran;
212        pHeadTranInHw = pQueue->pHeadTranInHw;
213        pTailTranInHw = pQueue->pTailTranInHw;
214       
215        BDBG_ASSERT( ulLastAssignedId < ulNumQueueEntries );
216
217        ulTranEntry = 0;
218        while ( ulTranEntry < ulNumQueueEntries )
219        {
220                /* assert for the first block of the Tran */
221                pTranEntry = pQueue->pHeadEntry + ulTranEntry;
222                ulNumBlocks = pTranEntry->ulNumTranBlocks;
223                BDBG_ASSERT( (0 < ulNumBlocks) && (ulNumBlocks <= ulMaxNumBlkPerTran) );
224
225                /* assert for all remaining blocks of the Tran */
226                ulBlockEntryLimit = ulTranEntry + ulNumBlocks; /* 1st block outside of the Tran */
227                for ( ulBlockEntry = ulTranEntry+1; ulBlockEntry < ulBlockEntryLimit; ulBlockEntry ++ )
228                {
229                        pBlockEntry = pQueue->pHeadEntry + ulBlockEntry;
230                        BDBG_ASSERT( 1 == pBlockEntry->ulNumTranBlocks );
231                        BDBG_ASSERT( BDMA_TranStatus_eUnknown == pBlockEntry->eStatus );
232                }
233
234                /* we will assert if pTailTranInHw, pHeadTranInHw
235                 * and ulLastAssignedId are found */
236                if ( ulTranEntry == ulLastAssignedId )
237                        bSeeLastAssigned = true;
238                if ( pTranEntry == pTailTranInHw )
239                        bSeeLastIssued = true;
240                if ( pTranEntry == pHeadTranInHw ) 
241                        bSee1stUnFinished = true;
242
243                /* prepare for next pass of the loop */
244                ulTranEntry = ulBlockEntry;
245        }
246
247        BDBG_ASSERT( ulTranEntry == ulNumQueueEntries );
248        BDBG_ASSERT( bSeeLastAssigned );
249        BDBG_ASSERT( (bSeeLastIssued)    || (NULL == pTailTranInHw) );
250        BDBG_ASSERT( (bSee1stUnFinished) || (NULL == pHeadTranInHw) );
251}
252
253
254/*--------------------------------------------------------------------------
255 * {private}
256 * BDMA_P_Queue_CheckNextDescInHw_isr
257 *
258 * To be called to assert that the queue is not corrupted.
259 * It should be called only if we are debugging or if some fetal error happened
260*/
261static void BDMA_P_Queue_CheckNextDescInHw_isr
262        ( BDMA_P_QueueContext *    pQueue )
263{
264        uint32_t ulTranEntry;    /* Entry index of the Tran's 1st Entry */
265        BDMA_P_QueueEntry *  pTranEntry;  /* Entry ptr of the Tran's 1st Entry */
266        BDMA_P_QueueEntry *  pHeadTranInHw;
267        BDMA_P_QueueEntry *  pTailTranInHw;
268        uint32_t ulNumQueueEntries;
269        bool  bSeeLastIssued = false;
270       
271        BDBG_ASSERT( NULL != pQueue );
272       
273        ulNumQueueEntries = pQueue->CmnSettings.ulTotalNumBlocks;
274        pHeadTranInHw = pQueue->pHeadTranInHw;
275        pTailTranInHw = pQueue->pTailTranInHw;
276       
277        /* assert relation of pHeadTranInHw, and pTailTranInHw */
278        BDBG_ASSERT( (NULL != pHeadTranInHw) == (NULL != pTailTranInHw) );
279        if ( NULL != pHeadTranInHw )
280        {
281                /* assert pTailTranInHw IS linked to pHeadTranInHw */
282                bSeeLastIssued = false;
283                ulTranEntry = 0;
284                pTranEntry = pHeadTranInHw;
285                while ( ulTranEntry < ulNumQueueEntries )
286                {
287                        if ( pTranEntry == pTailTranInHw )
288                        {
289                                (*pQueue->pCheckNextDesc_isr)(pTranEntry, NULL);
290                                bSeeLastIssued = true;
291                                break;
292                        }
293                        else
294                        {
295                                (*pQueue->pCheckNextDesc_isr)(pTranEntry, pTranEntry->pNextTran);
296                                                               
297                                if (NULL == pTranEntry->pNextTran)
298                                {
299                                        BDBG_ERR(("Fetal error: bad Tran at entry %d between pHeadTranInHw at %d pTailTranInHw at %d",
300                                                          pTranEntry - pQueue->pHeadEntry,
301                                                          pHeadTranInHw - pQueue->pHeadEntry,
302                                                          pTailTranInHw - pQueue->pHeadEntry));
303                                        return;
304                                }
305                                ulTranEntry += pTranEntry->ulNumTranBlocks;
306                                pTranEntry = pTranEntry->pNextTran;
307                                BDBG_ASSERT(NULL != pTranEntry);
308                        }
309                }
310                BDBG_ASSERT(bSeeLastIssued);
311        }
312}
313
314
315/***************************************************************************
316 *
317 * Static Utility Functions for Sub-Module Queue
318 *
319 **************************************************************************/
320
321/***************************************************************************
322 * {private}
323 * BDMA_P_Queue_DummyTryLock_isr
324 */
325static bool BDMA_P_Queue_DummyTryLock_isr
326        ( void *                   pvParm1,
327          int                      iParm2 )
328{
329        BSTD_UNUSED(pvParm1);
330        BSTD_UNUSED(iParm2);
331
332        return true;
333}
334
335/***************************************************************************
336 * {private}
337 * BDMA_P_Queue_DummyReleaseLock_isr
338 */
339static bool BDMA_P_Queue_DummyReleaseLock_isr
340        ( void *                   pvParm1,
341          int                      iParm2 )
342{
343        BSTD_UNUSED(pvParm1);
344        BSTD_UNUSED(iParm2);
345
346        return true;
347}
348
349/*--------------------------------------------------------------------------
350 * {private}
351 * BDMA_P_Queue_ProcDoneStatus_isr
352 *
353 * Static utility to process dma-done HW status
354 */
355static void BDMA_P_Queue_ProcDoneStatus_isr
356        ( BDMA_P_QueueHandle       hQueue )
357{
358        BDMA_P_QueueContext * pQueue;
359        BDMA_P_QueueEntry  *pHeadTranInHw, *pTailTranInHw;     
360        BDMA_P_QueueEntry  *pTran;
361        bool  bSgOpenInHw;
362       
363        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );     
364        BDBG_ASSERT( NULL != pQueue ); 
365       
366        /* all Trans in HW have completed, but pHeadTranInHw could be NULL */
367        bSgOpenInHw = pQueue->bSgOpenInHw;
368        pHeadTranInHw = pQueue->pHeadTranInHw;
369        pTailTranInHw = pQueue->pTailTranInHw;
370        pTran = pHeadTranInHw;
371        while (NULL != pTran)
372        {
373                pHeadTranInHw = pTran->pNextTran;
374
375                pTran->eStatus = BDMA_TranStatus_eSucceeded;
376                pTran->pNextTran = NULL;
377               
378                /* let user's call back func further process done-info.
379                 * likely user will check the status of the done Tran
380                 * and issue another DMA transfer
381                 */
382                if (NULL != pTran->pCallBackFunc_isr)
383                {
384                        (*pTran->pCallBackFunc_isr) (
385                                pTran->pUserCallBackParam, pTran, BDMA_TranStatus_eSucceeded);
386                }
387
388                /* continue the loop */
389                pTran = pHeadTranInHw;
390        }
391       
392        /* no more Tran progress in HW */
393        pQueue->pHeadTranInHw = NULL;
394        pQueue->pTailTranInHw = NULL;
395
396        BDBG_MSG(("\t\t\tDone with last Tran in Hw at entry %d, bSgOpenInHw = %d",
397                          pTran - pQueue->pHeadEntry, bSgOpenInHw));
398}
399
400#if BDMA_P_USE_CURR_DESC_ADDR
401/*--------------------------------------------------------------------------
402 * {private}
403 * BDMA_P_Queue_ProcInProgStatus_isr
404 *
405 *  Static utility to process dma-in-progress HW status
406 */
407static void BDMA_P_Queue_ProcInProgStatus_isr
408        ( BDMA_P_QueueHandle       hQueue,
409          uint32_t                 ulHwActDesc )
410{
411        BDMA_P_QueueContext * pQueue;
412        BDMA_P_QueueEntry  *pTran, *pNextTran;
413       
414        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
415        BDBG_ASSERT( NULL != pQueue );
416
417        /* all Trans before the entry that has desc ulHwActDesc have completed */
418        pTran = pQueue->pHeadTranInHw; 
419        while (NULL != pTran)
420        {
421                if ((ulHwActDesc >= pTran->ulDescPhysAddr) &&
422                        (ulHwActDesc <= (pTran + (pTran->ulNumActBlocks - 1))->ulDescPhysAddr))
423                {
424                        /* hardware working on this transaction.
425                         * note: eStatus != eSuccess if this func is called */
426                        break;
427                }
428
429                /* pTran is completed: HW is with next Tran */
430                BDBG_MSG(("\t\t\tmark tran at entry %d as success", 
431                                  pTran - pQueue->pHeadEntry));
432               
433                pNextTran = pTran->pNextTran;
434                pTran->eStatus = BDMA_TranStatus_eSucceeded;
435                pTran->pNextTran = NULL;
436               
437                /* let user's call back func further process done-info.
438                 * likely user will check the status of the done Tran
439                 * and issue another DMA transfer
440                 */
441                if (NULL != pTran->pCallBackFunc_isr)
442                {
443                        (*pTran->pCallBackFunc_isr) (
444                                pTran->pUserCallBackParam, pTran, BDMA_TranStatus_eSucceeded);
445                }
446
447                /* continue the loop */
448                pTran = pNextTran;
449        }
450       
451        /* the first Tran in HW not completed yet */
452        pQueue->pHeadTranInHw = pTran;
453       
454        BDBG_MSG(("\t\t\t1stUnFinishedTran at entry %d", pTran - pQueue->pHeadEntry));
455}
456#endif
457
458/*--------------------------------------------------------------------------
459 * {private}
460 * BDMA_P_Queue_SendToHw_isr
461 *
462 * Static utility to send to send the Trans queued in SW into HW
463 */
464static void BDMA_P_Queue_SendToHw_isr
465        ( BDMA_P_QueueHandle       hQueue,
466          BDMA_P_HwStatus          eStatus,
467          bool                     bAppendInHw)
468{
469        BDMA_P_QueueContext * pQueue;
470       
471        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
472        BDBG_ASSERT( NULL != pQueue );
473
474#if (1 == BDMA_P_SHOW_DYN_LINK_FAIL)   
475        BDMA_P_Queue_CheckQCorruption_isr(pQueue);
476        BDMA_P_Queue_CheckNextDescInHw_isr(pQueue);
477#endif
478       
479        /* start dma in hw: append desc if bAppendInHw */
480        (*pQueue->pSendToHw_isr) (hQueue, eStatus, bAppendInHw);
481
482        /* in case last dyn linking fails */
483        pQueue->pPreLinkTailTranInHw = (bAppendInHw)? pQueue->pTailTranInHw : NULL;
484        pQueue->bPreLinkSgOpenInHw = pQueue->bSgOpenInHw;
485 
486        pQueue->bSgOpenInHw = pQueue->bSgOpenInQ;
487
488        if ((NULL != pQueue->pHeadTranInHw)&&(pQueue->pTailTranInHw != NULL))
489                pQueue->pTailTranInHw->pNextTran = pQueue->pHeadTranInQ;
490        else
491                pQueue->pHeadTranInHw = pQueue->pHeadTranInQ;
492        pQueue->pTailTranInHw = pQueue->pTailTranInQ;
493
494        pQueue->pHeadTranInQ = NULL;
495        pQueue->pTailTranInQ = NULL;
496
497        pQueue->bHwStarted = true;
498}
499
500
501/***************************************************************************
502 *
503 * Exported Queue Functions
504 *
505 **************************************************************************/
506
507/***************************************************************************
508 * {private}
509 * BDMA_P_Queue_Create
510 *
511 * To be called to create queue for a dma channel. It allocates a queue entry
512 * array from system memory, and contiguous descriptor array from BMEM.
513 * It then initiate the allocated queue array, including setting each
514 * queue-entry to point to the descriptor of the same index.
515 *
516 * Note: assume parameters are valid
517 */
518BERR_Code BDMA_P_Queue_Create
519        ( BDMA_P_QueueHandle *      phQueue,
520          void *                    hEngine,
521          BMEM_Handle               hMemory,
522          uint32_t                  ulNumWordsPerDesc,
523          const BDMA_P_CmnSettings *pCmnSettings,
524          BDMA_P_ReadHwRegsFunc         pReadHwRegs_isr,
525          BDMA_P_AppendTranDescFunc     pAppendTranDesc_isr,
526          BDMA_P_SendToHwFunc       pSendToHw_isr,
527          BDMA_P_CheckNextDescFunc  pCheckNextDesc_isr,
528          BDMA_P_SafeToSendHwFunc   pSafeToSendHw_isr)
529{
530        BDMA_P_QueueContext *  pQueue = NULL;
531        BDMA_P_QueueEntry *    pQueueEntry = NULL;
532        uint32_t *             pulDesc = NULL;
533        BDMA_P_QueueEntry * pEntry;
534        BERR_Code eResult = BERR_SUCCESS;
535        uint32_t  ulNumQueueEntries= 0;
536        uint32_t  ulDescBufSize = 0;
537        uint32_t  ulId =0;
538        void * pCachedAddr = NULL;
539
540        BDBG_ASSERT( NULL != phQueue );
541        BDBG_ASSERT( NULL != hMemory );
542        BDBG_ASSERT( 0 != ulNumWordsPerDesc );
543        BDBG_ASSERT( NULL != pCmnSettings );
544        BDBG_ASSERT( NULL != pReadHwRegs_isr );
545        BDBG_ASSERT( NULL != pAppendTranDesc_isr );
546        BDBG_ASSERT( NULL != pSendToHw_isr );
547        BDBG_ASSERT( NULL != pCheckNextDesc_isr );
548        BDBG_ASSERT( NULL != pSafeToSendHw_isr);
549
550        /* allocate and clear QueueContext (i.e. queue) */
551        pQueue = (BDMA_P_QueueContext *)BKNI_Malloc( sizeof(BDMA_P_QueueContext) );
552        if ( NULL == pQueue )
553        {
554                eResult = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
555                goto BDMA_P_Err_Queue_Create;           
556        }
557        BKNI_Memset((void*)pQueue, 0x0, sizeof(BDMA_P_QueueContext));
558       
559        /* allocate and clear Queue Entries (i.e. Blocks) */
560        ulNumQueueEntries = pCmnSettings->ulTotalNumBlocks;
561        pQueueEntry = (BDMA_P_QueueEntry *)BKNI_Malloc( (1 + ulNumQueueEntries) * sizeof(BDMA_P_QueueEntry) );
562        if ( NULL == pQueueEntry )
563        {
564                eResult = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
565                goto BDMA_P_Err_Queue_Create;           
566        }
567        BKNI_Memset((void*)pQueueEntry, 0x0, (1 + ulNumQueueEntries) * sizeof(BDMA_P_QueueEntry));
568
569        /* allocate desc array: it has to be physically present and contiguous
570         * (required by io dma ), therefore should use BMEM */
571        ulDescBufSize = ulNumQueueEntries * ulNumWordsPerDesc * 4;
572        pulDesc = (uint32_t *) BMEM_AllocAligned(
573                hMemory, ulDescBufSize, 6, 0 ); /* 6 ==> 2^6 = 64 bytes alligned */ 
574        if ( NULL == pulDesc )
575        {
576                eResult = BERR_TRACE(BERR_OUT_OF_DEVICE_MEMORY);
577                goto BDMA_P_Err_Queue_Create;
578        }
579        BKNI_Memset((void*)pulDesc, 0x0, ulDescBufSize);
580
581        /* initialize queue entries */
582        for (ulId=0; ulId<ulNumQueueEntries; ulId++)
583        {
584                pEntry = pQueueEntry + ulId;
585               
586                /*pEntry->bBlockInfoSet = false;
587                pEntry->bCachedDscrp = false;
588                pEntry->ulSgStartStop = 0;
589                pEntry->ulNumActBlocks = 0;
590                pEntry->bSgStartStopSet = false;
591                pEntry->bSgEnable = false;
592                pEntry->ulKeySlot = 0;
593                pEntry->eCryptMode = BDMA_CryptMode_eNoCrypt;*/
594                pEntry->ulNumTranBlocks = 1; /* assert(0!=ulNumTranBlocks)*/
595                pEntry->pulDescAddr = pulDesc + ulId * ulNumWordsPerDesc;
596                eResult = BMEM_ConvertAddressToCached(hMemory, (void*) pEntry->pulDescAddr,
597                        &pCachedAddr);
598                if (BERR_SUCCESS != eResult)
599                {
600                        goto BDMA_P_Err_Queue_Create;
601                }
602                /* this extra assignment is to fix a strict-aliasing compile warning */ 
603                pEntry->pulCachedDescAddr = (uint32_t *)pCachedAddr;
604                BMEM_ConvertAddressToOffset(hMemory, (void*) pEntry->pulDescAddr,
605                        &pEntry->ulDescPhysAddr);
606                pEntry->eStatus = BDMA_TranStatus_eUnknown;
607                BDMA_P_TRAN_SET_BLACK_MAGIC( pEntry );
608
609                BDBG_MSG(("Block %d: pulDescAddr 0x%08lx, pulCachedDescAddr 0x%08lx",
610                                  ulId, pEntry->pulDescAddr, pEntry->pulCachedDescAddr));
611        }
612
613        /* this extra struct only means to make (pBlock + 1) valid,
614         * it is to make SetBlockInfo convenient */
615        pEntry = pQueueEntry + ulNumQueueEntries;
616        pEntry->ulNumTranBlocks = 1;
617                pEntry->pulDescAddr = pQueueEntry->pulDescAddr;
618        pEntry->pulCachedDescAddr = pQueueEntry->pulCachedDescAddr;
619        pEntry->eStatus = BDMA_TranStatus_eUnknown;
620
621        /* initialize BDMA_P_QueueContext */
622        /*pQueue->bSgOpenInHw = false;
623        pQueue->bSgOpenInQ = false;
624        pQueue->pHeadTranInHw = NULL;
625        pQueue->pTailTranInHw = NULL;
626        pQueue->pHeadTranInQueue = NULL;
627        pQueue->pTailTranInQueue = NULL;*/
628        pQueue->ulNumWordsPerDesc = ulNumWordsPerDesc;
629        pQueue->CmnSettings = *pCmnSettings;
630        pQueue->bDmaHwShared = (NULL != pCmnSettings->pTryLock_isr);
631        pQueue->pHeadEntry = pQueueEntry;
632        pQueue->ul1stDescPhysAddr = pQueueEntry->ulDescPhysAddr;
633        pQueue->ulLastDescPhysAddr =
634                (pQueueEntry + (ulNumQueueEntries - 1))->ulDescPhysAddr;       
635        pQueue->pReadHwRegs_isr = pReadHwRegs_isr;
636        pQueue->pAppendTranDesc_isr = pAppendTranDesc_isr;
637        pQueue->pSendToHw_isr = pSendToHw_isr;
638        pQueue->pCheckNextDesc_isr = pCheckNextDesc_isr;
639        pQueue->pSafeToSendHw_isr  = pSafeToSendHw_isr;
640        pQueue->ulIndx_LastEntryAssigned = ulNumQueueEntries - 1;
641        pQueue->hEngine = hEngine;
642        BDMA_P_QUEUE_SET_BLACK_MAGIC( pQueue );
643
644        /* use dummy TryLock/ReleaseLock to avoid "if" in code if it is not provided */
645        if (NULL == pCmnSettings->pTryLock_isr)
646        {
647                pQueue->CmnSettings.pTryLock_isr = BDMA_P_Queue_DummyTryLock_isr;
648                pQueue->CmnSettings.pReleaseLock_isr = BDMA_P_Queue_DummyReleaseLock_isr;
649        }
650       
651        *phQueue = pQueue;
652        return eResult;
653
654  BDMA_P_Err_Queue_Create:
655        /* free allocated buf */
656        if ( NULL != pQueue )
657                BDMA_P_QUEUE_DESTROY_CONTEXT(pQueue);
658        if ( NULL != pQueueEntry )
659                BDMA_P_QUEUE_DESTROY_ENTRY(pQueueEntry, ulNumQueueEntries);
660        if ( NULL != pulDesc )
661                BDMA_P_QUEUE_DESTROY_DESC( hMemory, pulDesc, ulDescBufSize);
662       
663        *phQueue = NULL;
664        return eResult;
665}
666
667/***************************************************************************
668 * {private}
669 * BDMA_P_Queue_Destroy
670 *
671 * To be called to destroy the queue.
672 *
673 * Note: assume parameters are valid
674 */
675BERR_Code BDMA_P_Queue_Destroy
676        ( BDMA_P_QueueHandle        hQueue,
677          BMEM_Handle               hMemory )
678{
679        BDMA_P_QueueContext * pQueue;   
680        BDMA_P_QueueEntry * pFirstEntry;
681        uint32_t  ulDescBufSize;
682       
683        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
684        BDBG_ASSERT( NULL != pQueue );
685        BDBG_ASSERT( NULL != hMemory );
686        BDMA_P_QUEUE_ASSERT_UNCORRUPT( pQueue );
687       
688        /* TODO: make sure HW is idle ??? */
689       
690        /* free allocated buf */
691        if ( NULL != pQueue )
692        {
693                pFirstEntry = pQueue->pHeadEntry;
694                if ( NULL != pFirstEntry )
695                {
696                        if ( NULL != pFirstEntry->pulDescAddr )
697                        {
698                                ulDescBufSize = pQueue->CmnSettings.ulTotalNumBlocks *
699                                        pQueue->ulNumWordsPerDesc * 4;
700                                BDMA_P_QUEUE_DESTROY_DESC( hMemory,
701                                        pFirstEntry->pulDescAddr, ulDescBufSize );
702                        }
703                        BDMA_P_QUEUE_DESTROY_ENTRY(
704                                pFirstEntry, pQueue->CmnSettings.ulTotalNumBlocks);
705                }
706                BDMA_P_QUEUE_DESTROY_CONTEXT( pQueue );
707        }
708
709        return BERR_SUCCESS;
710}
711
712/***************************************************************************
713 * {private}
714 * BDMA_P_Queue_GetEngine_isr
715 *
716 * To be called to get the dma engine
717 *
718 * Note: assume parameters are valid
719 */
720void * BDMA_P_Queue_GetEngine_isr
721        ( BDMA_P_QueueHandle        hQueue )
722{
723        BDMA_P_QueueContext * pQueue;   
724
725        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
726        BDBG_ASSERT( NULL != pQueue );
727
728        return pQueue->hEngine;
729}
730
731#define BDMA_P_NUM_TRY_READ            (5)
732/*--------------------------------------------------------------------------
733 * {private}
734 * BDMA_P_Queue_ReadHwReg_isr
735 *
736 *  Static utility to check whether the values returned by HW register
737 *  reading looks good
738 */
739static bool BDMA_P_Queue_ReadHwReg_isr
740        ( BDMA_P_QueueContext     *pQueue,
741          BDMA_P_HwStatus         *peStatus,
742          uint32_t                *pulHwActDesc,
743          uint32_t                *pulScratchReg)
744{
745        BDMA_P_QueueEntry  *pLastTranInHw, *pLastEntryInHw;
746        BDMA_P_QueueEntry  *pNewHeadTranInQ, *pPreLinkTailTranInHw, *pPreLinkLastEntryInHw;
747        BDMA_P_HwStatus  eStatus;
748        uint32_t  ulHwActDesc, ulHw1stDesc, ulWaterMark, ulScratchReg, ulLastDesc;
749        uint32_t  ul1stDescInQ, ulLastDescInQ;
750        bool  bBadHwDescAddr, bBadWaterMark, bMisMatch, bHwEndDescMisMatch = true;
751        uint32_t  ulOff, ulOffMask;
752        int  ii;
753
754        BDBG_ASSERT( NULL != pQueue );
755        BDBG_ASSERT( NULL != peStatus );
756        BDBG_ASSERT( NULL != pulHwActDesc );
757        BDBG_ASSERT( NULL != pulScratchReg );
758        BDBG_ASSERT((NULL == pQueue->pHeadTranInHw) == (NULL == pQueue->pTailTranInHw));
759
760        /* some customer team found HW regsiter reading might return junk value */
761        ulOffMask = (8 == pQueue->ulNumWordsPerDesc)? 0xFFF0001F: 0xFFF0000F;
762        ul1stDescInQ  = pQueue->ul1stDescPhysAddr;
763        ulLastDescInQ = pQueue->ulLastDescPhysAddr;
764        pLastTranInHw = pQueue->pTailTranInHw;
765        pLastEntryInHw = (NULL != pLastTranInHw)?
766                pLastTranInHw + (pLastTranInHw->ulNumActBlocks - 1) : NULL;
767        for (ii=0; ii<BDMA_P_NUM_TRY_READ; ii++)
768        {
769                /* read HW registers */
770                (*pQueue->pReadHwRegs_isr)(
771                        pQueue->hEngine, &eStatus, &ulHwActDesc, &ulScratchReg);
772
773                /* validate the reg reading */
774               
775                ulHw1stDesc = ulScratchReg & ~BDMA_P_WATER_MARK_MASK;
776                ulWaterMark = ulScratchReg & BDMA_P_WATER_MARK_MASK;
777                ulOff = ulHwActDesc - ulHw1stDesc;
778
779       
780                bBadWaterMark = ((ulWaterMark != BDMA_P_WATER_MARK_SG_OPEN) &&
781                                                 (ulWaterMark != BDMA_P_WATER_MARK_SG_CLOSE));
782                bBadHwDescAddr = (0 != (ulOff & ulOffMask));
783        if (( pLastTranInHw != NULL) &&(pLastTranInHw->ulFirstBlock))
784        {
785                        ulLastDesc = pLastTranInHw->ulDescPhysAddr + (((pLastTranInHw->ulNumActBlocks-1)+pLastTranInHw->ulFirstBlock)*4*8/*BDMA_P_MEM_NUM_WORDS_PER_DESC*/);
786                        bHwEndDescMisMatch = ( ulLastDesc != ulHwActDesc );
787        }
788               
789                bMisMatch = (((BDMA_P_HwStatus_eSleep == eStatus)             &&
790                                          (NULL != pLastTranInHw)                         &&
791                                          (pLastEntryInHw->ulDescPhysAddr != ulHwActDesc) &&
792                                          bHwEndDescMisMatch )                            ||
793                                         ((BDMA_P_HwStatus_eIdle == eStatus)              &&
794                                          (pQueue->bHwStarted)));
795               
796                *peStatus = eStatus;
797                *pulHwActDesc = ulHwActDesc;
798                *pulScratchReg = ulScratchReg;
799                if ((BDMA_P_HwStatus_eUnknown == eStatus) ||
800                        ((BDMA_P_HwStatus_eIdle != eStatus) &&
801                         (bBadWaterMark || bBadHwDescAddr || bMisMatch)))
802                {
803                        /* note: we occasionally see dynamic linking failure when HW is working on the
804                         * last desc as we perform the dyn linking. (why XXX ???)
805                         * re-wind Q record if it is only because that the last dynamic linking failed */
806                        pPreLinkTailTranInHw = pQueue->pPreLinkTailTranInHw;
807                        pPreLinkLastEntryInHw = (NULL != pPreLinkTailTranInHw)?
808                                pPreLinkTailTranInHw + (pPreLinkTailTranInHw->ulNumActBlocks - 1) : NULL;
809                        if ((NULL != pPreLinkTailTranInHw) &&
810                                (BDMA_TranStatus_eInProgress == pPreLinkTailTranInHw->eStatus) &&
811                                (pPreLinkLastEntryInHw->ulDescPhysAddr == ulHwActDesc) &&
812                                (BDMA_P_HwStatus_eSleep == eStatus) &&
813                                (false == bBadWaterMark) &&
814                                (false == bBadHwDescAddr))
815                        {
816#if (1 == BDMA_P_SHOW_DYN_LINK_FAIL)   
817                                BDBG_ERR(("last dyn link failed, rewind. now LastDescInHw 0x%08lx",
818                                                  pPreLinkLastEntryInHw->ulDescPhysAddr));
819#endif
820                                pNewHeadTranInQ = pPreLinkTailTranInHw->pNextTran;
821                                if (NULL != pQueue->pHeadTranInQ)
822                                {
823                                        (*pQueue->pAppendTranDesc_isr)(pNewHeadTranInQ, pQueue->pHeadTranInQ);
824                                        pNewHeadTranInQ->pNextTran = pQueue->pHeadTranInQ;
825                                }
826                                else
827                                {
828                                        pQueue->pTailTranInQ = pNewHeadTranInQ;
829                                        pNewHeadTranInQ->pNextTran = NULL;
830                                }
831                                pQueue->pHeadTranInQ = pNewHeadTranInQ;
832                               
833                                pPreLinkTailTranInHw->pNextTran = NULL;
834                                pQueue->pTailTranInHw = pPreLinkTailTranInHw;
835                                pQueue->bSgOpenInHw = pQueue->bPreLinkSgOpenInHw;
836                               
837                                pQueue->pPreLinkTailTranInHw = NULL;
838                                return true;
839                        }
840
841                        /* this read is invalid */
842                        BDBG_ERR(("see bad HW reg read: eStatus %d, HwActDesc 0x%08lx, Scratch 0x%08lx",
843                                          eStatus, ulHwActDesc, ulScratchReg));
844                        BDBG_ERR(("bBadWaterMark %d bBadHwDescAddr %d bMisMatch %d, ulHwLastDesc 0x%08lx",
845                                          bBadWaterMark? 1: 0, bBadHwDescAddr? 1 : 0, bMisMatch? 1: 0,
846                                          (pLastEntryInHw)? pLastEntryInHw->ulDescPhysAddr : 0));
847                }
848                else
849                {
850                        /*BDBG_MSG(("good HW reg read: eStatus %d, HwActDesc 0x%08lx, ulHwLastDesc 0x%08lx",
851                          eStatus, ulHwActDesc, (pLastEntryInHw)? pLastEntryInHw->ulDescPhysAddr : 0));*/
852                        pQueue->pPreLinkTailTranInHw = NULL;
853                        return true;
854                }
855        }
856        pQueue->pPreLinkTailTranInHw = NULL;
857       
858        /* we read BDMA_P_NUM_TRY_READ times and failed */
859        if (pQueue->bHwStarted)
860        {
861                BDBG_ERR(("bad HW reg read: eStatus %d, HwActDesc 0x%08lx, Scratch 0x%08lx",
862                                  eStatus, ulHwActDesc, ulScratchReg));
863                BDBG_ERR(("Queue 1st desc 0x%08lx, last desc 0x%08lx", ul1stDescInQ, ulLastDescInQ));
864
865                BDMA_P_Queue_CheckQCorruption_isr(pQueue);
866                BDMA_P_Queue_CheckNextDescInHw_isr(pQueue);
867        }
868       
869        /* if app exit and re-run, we might have mismatched status at beginning.
870         * XXX TODO: how to handle app re-start when reg has mismatched values, and
871         * not break multiple bdma instances algorithm? */
872        return false;
873}
874
875/*--------------------------------------------------------------------------
876 * {private}
877 * BDMA_P_Queue_CheckHwAndSendNewReq_isr
878 *
879 * Called to check HW status, process it, and try to send the Trans queued
880 * in SW into HW
881 */
882void BDMA_P_Queue_CheckHwAndSendNewReq_isr
883        ( BDMA_P_QueueHandle       hQueue )
884{
885        BDMA_P_QueueContext * pQueue;
886
887        BDMA_P_CmnSettings  *pSettings;
888        BDMA_P_QueueEntry  *pTailTranInHw;
889        uint32_t  ulHwActDesc = 0;
890        uint32_t  ulScratchReg = 0;
891        BDMA_P_HwStatus  eStatus;
892        bool  bGotLock, bRegReadOk;
893        bool  bHwSleep, bSgOpenInHw, bOwnHw, bAppendInHw, bSendToHw;
894               
895        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
896        BDBG_ASSERT( NULL != pQueue );
897
898        /* ensure dma done _isr is quarded by critical section */
899        BDBG_ASSERT(0 == pQueue->ulLockMark);
900        pQueue->ulLockMark++;
901
902        BDMA_P_QUEUE_ASSERT_UNCORRUPT( pQueue );
903        BDMA_P_QUEUE_CHECK_NEXT_DESC( pQueue );
904
905        bGotLock = false;
906    if ((NULL == pQueue->pHeadTranInQ) && (NULL == pQueue->pHeadTranInHw))
907                /* nothing to do */
908                goto CleanUp;
909
910        pSettings = &(pQueue->CmnSettings);
911        bSgOpenInHw = true;  /* worst senario */
912        bHwSleep = false;
913        bOwnHw = ! pQueue->bDmaHwShared;
914        eStatus = BDMA_P_HwStatus_eUnknown;
915        bGotLock =
916                (*pSettings->pTryLock_isr) (pSettings->pvParm1, pSettings->iParm2);
917       
918        bRegReadOk = BDMA_P_Queue_ReadHwReg_isr(
919                pQueue, &eStatus, &ulHwActDesc, &ulScratchReg);
920        pQueue->pSafeToSendHw_isr(hQueue, &eStatus);
921       
922        if ((NULL != pQueue->pHeadTranInHw) &&
923                (bRegReadOk))
924        {
925                /* this BDMA instance has sent its transfer list into
926                 * hardware, now the result is checked and processed */
927
928                if (/* some other BDMA instance already grab HW from us */
929#if BDMA_P_USE_CURR_DESC_ADDR
930                        ((ulHwActDesc < pQueue->ul1stDescPhysAddr) &&
931                         (ulHwActDesc > pQueue->ulLastDescPhysAddr)) ||
932#endif
933                        /* still owned by this BDMA instance, but dma done */
934                        (BDMA_P_HwStatus_eSleep == eStatus))
935                        /* ReadHwReg_isr already check the case that dma cmd still in bus */
936                {
937                        /* the request of this BDMA instance have completed in HW,                     
938                         * mark success and call user call-back for all trans done-in-Hw,
939                         * and update pHead/TrailTranInHw */
940                        BDMA_P_Queue_ProcDoneStatus_isr(hQueue);
941                }
942#if BDMA_P_USE_CURR_DESC_ADDR
943                else 
944                {
945                        /* this BDMA still own the HW, the dma req might-not completed yet
946                         * mark success and call user call-back for done-trans */
947                        BDMA_P_Queue_ProcInProgStatus_isr(hQueue, ulHwActDesc);
948                }
949#endif
950        }
951        /* else this instance has no req in HW, no need to check result */
952
953    if (NULL != pQueue->pHeadTranInQ)
954    {
955                /* there are Tran queued in sw, try to send it to hw */
956                if (bGotLock && (bRegReadOk || !pQueue->bHwStarted))
957                {
958            /* if current HW owner's last request in HW completed, we can grab
959                         * the HW now.
960                         * Note: check eStatus alone might not be enough if we read while
961                         *       a new dma was sent to HW but status not changed yet, but
962                         *       this case has been checked by ReadHwReg_isr. It will read
963                         *       one more time in this case.
964                         * note: we use (scrach & BDMA_P_WATER_MARK_MASK) to indicate
965                         *       bSgOpenInHw */
966                        bSgOpenInHw = 
967                                (BDMA_P_WATER_MARK_SG_OPEN == (ulScratchReg & BDMA_P_WATER_MARK_MASK));
968            bHwSleep = ((BDMA_P_HwStatus_eIdle  == eStatus) ||
969                                                (BDMA_P_HwStatus_eSleep == eStatus));
970                        bOwnHw = ((ulHwActDesc >= pQueue->ul1stDescPhysAddr) &&
971                                          (ulHwActDesc <= pQueue->ulLastDescPhysAddr));
972                }
973
974                pTailTranInHw = pQueue->pTailTranInHw;
975#if BDMA_P_SUPPORT_MEM_DMA_AUTO_APPEND
976                /* if pQueue->bSgOpenInHw, we can always dynamically link new dma req
977                 * in HW, even if we did not get Lock. When we failed to get Lock, this
978                 * is also the only case we will send new dma req to HW */
979                bSendToHw = (bOwnHw || pQueue->bSgOpenInHw || (bHwSleep && !bSgOpenInHw));
980#else
981                /* for those chips that don't support auto_append there is a HW bug
982                 * with dynamic append when scater-gather is active */
983                bSendToHw = ((bOwnHw && !pQueue->bSgOpenInHw) ||
984                                         (bHwSleep && (!bSgOpenInHw || pQueue->bSgOpenInHw)));
985#endif
986                bAppendInHw = ((NULL != pTailTranInHw) && (!bHwSleep));
987               
988                if (bSendToHw)
989                {
990                        BDMA_P_Queue_SendToHw_isr(hQueue, eStatus, bAppendInHw);
991                }
992        }
993       
994  CleanUp:             
995        if (bGotLock)
996        {
997                (*pSettings->pReleaseLock_isr)(
998                        pSettings->pvParm1, pSettings->iParm2);
999        }       
1000        pQueue->ulLockMark--;
1001}
1002
1003/*--------------------------------------------------------------------------
1004 * {private}
1005 * BDMA_P_Queue_ReInitBlocks_isr
1006 *
1007 * static utility used in this file. No validation. It makes the chunk of
1008 * blocks following ulFirstEntryId as one destroyed Tran
1009 */
1010static void BDMA_P_Queue_ReInitBlocks_isr(
1011        BDMA_P_QueueContext *pQueue,
1012        BDMA_P_QueueEntry *  pFirstEntry,
1013        uint32_t             ulNumBlocks )
1014{
1015        BDMA_P_QueueEntry *  pEntry;
1016        uint32_t  ulLoopCntr;
1017        uint32_t  ulDescNumWords;
1018
1019        ulDescNumWords = pQueue->ulNumWordsPerDesc;
1020        for ( ulLoopCntr = 0; ulLoopCntr < ulNumBlocks; ulLoopCntr++ )
1021        {
1022                pEntry = pFirstEntry + ulLoopCntr;
1023               
1024                pEntry->eStatus = BDMA_TranStatus_eUnknown;
1025                pEntry->bBlockInfoSet = false;
1026                pEntry->bCachedDscrp = false;
1027                pEntry->ulSgStartStop = 0;
1028                pEntry->ulNumActBlocks = 0;
1029                pEntry->ulNumTranBlocks = 1; /* assert(0!=ulNumTranBlocks)*/
1030                pEntry->pCallBackFunc_isr = NULL;
1031                pEntry->pUserCallBackParam = NULL;
1032                pEntry->bSgStartStopSet = false;
1033                pEntry->bSgEnable = false;
1034                pEntry->ulKeySlot = 0;
1035                pEntry->eCryptMode = BDMA_CryptMode_eNoCrypt;
1036       
1037                /* clean bSgStart/bSgEnd bits
1038                 * todo: use a call back func for this */
1039                if (ulDescNumWords > 4)
1040                        *(pEntry->pulDescAddr + 4) = 0; 
1041        }
1042
1043        /* re-init first block */
1044        pFirstEntry->ulNumTranBlocks = ulNumBlocks;
1045}
1046
1047/*--------------------------------------------------------------------------
1048 * {private}
1049 * BDMA_P_Queue_TryMakeTranHere_isr(
1050 *
1051 * static utility used by BDMA_P_Queue_CreateTran only. No validation.
1052 * It checks whether ulFirstEntryId has enough free following contiguous
1053 * blocks. Return ulNumBlocksNeeded if yes, return the real number of
1054 * free contiguous blocks if not. In the yes case, it also make the remaining
1055 * tail as a destroyed Tran
1056 */
1057static uint32_t BDMA_P_Queue_TryMakeTranHere_isr(
1058        BDMA_P_QueueContext * pQueue,
1059        uint32_t              ulFirstEntryId,
1060        uint32_t              ulNumBlocksNeeded )
1061{
1062        BDMA_P_QueueEntry *  pEntry;
1063        uint32_t ulNumFreeBlocks;
1064        uint32_t ulEntryId;
1065        uint32_t ulNumRemainBlocks;
1066        uint32_t ulNumQueueEntries;
1067       
1068        ulNumFreeBlocks = 0;
1069        ulEntryId = ulFirstEntryId;
1070        ulNumQueueEntries = pQueue->CmnSettings.ulTotalNumBlocks;
1071        while ( ulEntryId < ulNumQueueEntries )
1072        {
1073                pEntry = pQueue->pHeadEntry + ulEntryId;
1074                if ( BDMA_TranStatus_eUnknown == pEntry->eStatus )
1075                {
1076                        /* the chunk of blocks lead by this "FirstEntry" is free */
1077                        ulNumFreeBlocks += pEntry->ulNumTranBlocks;
1078                        if ( ulNumFreeBlocks >=  ulNumBlocksNeeded )
1079                        {
1080                                /* we got enough contiguous free blocks, init the new Tran */
1081                                BDMA_P_Queue_ReInitBlocks_isr(
1082                                        pQueue, pQueue->pHeadEntry + ulFirstEntryId, ulNumBlocksNeeded );
1083                                pEntry = pQueue->pHeadEntry + ulFirstEntryId;
1084                                pEntry->eStatus = BDMA_TranStatus_eCreated;
1085                               
1086                                /* make the Tran's remaining tail as a destroyed Tran */
1087                                ulNumRemainBlocks = ulNumFreeBlocks - ulNumBlocksNeeded;                               
1088                                if ( ulNumRemainBlocks > 0 )
1089                                {
1090                                        BDMA_P_Queue_ReInitBlocks_isr(pQueue,
1091                                                pQueue->pHeadEntry + ulFirstEntryId+ulNumBlocksNeeded,
1092                                                ulNumRemainBlocks );
1093                                }
1094
1095                                return ulNumBlocksNeeded;                               
1096                        }
1097                        else
1098                        {
1099                                /* need to continue to look at next Tran: one more loop pass */
1100                                ulEntryId += pEntry->ulNumTranBlocks;
1101                        }
1102                }
1103                else /* we hit an active Tran, still not got enough free blocks yet */
1104                {
1105                        break;
1106                }
1107        }
1108
1109        return ulNumFreeBlocks;
1110}
1111
1112/***************************************************************************
1113 * {private}
1114 * BDMA_P_Queue_CreateTran_isr
1115 *
1116 * To be called when a new transfer is created. It finds a free chunck of
1117 * contiguous queue entries (that corresponds to a set of contiguous
1118 * descriptors too) in the dma channel queue, and outputs the first entry
1119 * of the chunck.
1120 *
1121 * Note: assume parameters are valid,
1122 *       ulNumBlocks can not be 0
1123 */
1124BERR_Code BDMA_P_Queue_CreateTran_isr
1125        ( BDMA_P_QueueHandle       hQueue,
1126          uint32_t                 ulNumBlocks,
1127          bool                     bCachedDesc,
1128          BDMA_P_QueueEntry **     ppNewTran )
1129{
1130        BDMA_P_QueueContext * pQueue;
1131        uint32_t ulPreAssignedId;
1132        uint32_t ulNewAssignedId;
1133        BDMA_P_QueueEntry * pNewAssigned;               
1134        BDMA_P_QueueEntry * pPreAssigned;
1135        uint32_t ulNumBlockSeen, ulMaxNumBlockToSee;
1136        uint32_t ulNumFreeBlocks;
1137        uint32_t ulNumQueueEntries;
1138
1139        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
1140        BDBG_ASSERT( NULL != pQueue );
1141        BDBG_ASSERT( NULL != ppNewTran );
1142        BDBG_ASSERT( 0 != ulNumBlocks );
1143        BDBG_ASSERT( ulNumBlocks <= pQueue->CmnSettings.ulMaxNumBlocksPerTran );
1144        BDMA_P_QUEUE_ASSERT_UNCORRUPT( pQueue );
1145       
1146        *ppNewTran = NULL;
1147       
1148        /* find free contiguous entries */
1149        ulPreAssignedId = pQueue->ulIndx_LastEntryAssigned;
1150        pPreAssigned = pQueue->pHeadEntry + ulPreAssignedId;
1151
1152        /* The lastAssignedId might be free also, so should look one more time */
1153        ulNumQueueEntries = pQueue->CmnSettings.ulTotalNumBlocks;
1154        ulMaxNumBlockToSee = ulNumQueueEntries + pPreAssigned->ulNumTranBlocks;
1155        ulNumBlockSeen = 0;
1156        while ( ulNumBlockSeen < ulNumQueueEntries )
1157        {
1158                ulNewAssignedId = BDMA_P_QUEUE_WRAP_INDEX(
1159                        ulPreAssignedId + pPreAssigned->ulNumTranBlocks );
1160                pNewAssigned = pQueue->pHeadEntry + ulNewAssignedId;
1161
1162                /* try to get ulNumBlocks contiguous free blocks following
1163                 * ulNewAssignedId */
1164                ulNumFreeBlocks = BDMA_P_Queue_TryMakeTranHere_isr(
1165                        pQueue, ulNewAssignedId, ulNumBlocks );
1166
1167                if ( ulNumBlocks == ulNumFreeBlocks )
1168                {
1169                        /* This entry got enough contiguous following free blocks */
1170                        pQueue->ulIndx_LastEntryAssigned = ulNewAssignedId;
1171                        pNewAssigned->hQueue = hQueue;
1172                        pNewAssigned->bCachedDscrp = bCachedDesc;
1173                        *ppNewTran = pNewAssigned;                     
1174                        return BERR_SUCCESS;
1175                }
1176                else
1177                {
1178                        /* This entry does NOT have enough contiguous following free blocks
1179                         * skip this chunk and try another loop pass */
1180                        ulNumBlockSeen += (ulNumFreeBlocks + pPreAssigned->ulNumTranBlocks);
1181                        ulPreAssignedId = BDMA_P_QUEUE_WRAP_INDEX(
1182                                ulNewAssignedId + ulNumFreeBlocks );
1183                        pPreAssigned = pQueue->pHeadEntry + ulPreAssignedId;
1184                }
1185        }
1186
1187        /* we did not find a big enough contiguous free block chunk */
1188        return BERR_TRACE(BDMA_ERR_OUT_OF_QUEUE);
1189}
1190
1191/***************************************************************************
1192 * {private}
1193 * BDMA_P_Queue_StartTran_isr
1194 *
1195 * To be called to process the user calling of Start or StartAndCallBack. It
1196 * always returns eSuccess.
1197 *
1198 * pCallBackFunc_isr is assumed to indicate whether the Tran is sync or async.
1199 * No matter its is aync or async, it is always queued in sw first. Then the
1200 * Trans in sw Q is sent to HW if we can.
1201 *
1202 * Note: assume parameters are valid
1203 */
1204BERR_Code BDMA_P_Queue_StartTran_isr
1205        ( BDMA_P_QueueHandle       hQueue,
1206          BDMA_P_QueueEntry *      pTran,
1207          uint32_t                 ulNumActBlocks,
1208          bool                     bSgOpen, 
1209          BDMA_P_CallbackFunc      pCallBackFunc_isr,
1210          void *                   pUserCallBackParam )
1211{
1212        BDMA_P_QueueContext * pQueue;
1213       
1214        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
1215        BDBG_ASSERT( NULL != pQueue );
1216        BDBG_ASSERT( NULL != pTran );
1217
1218        /* can not re-start this Tran if it is still in prgress */
1219        if (BDMA_TranStatus_eInProgress == pTran->eStatus)
1220        {
1221                BDBG_ERR(("re-start in prog tran at entry %d", pTran - pQueue->pHeadEntry));
1222                return BERR_TRACE(BDMA_ERR_TRAN_IN_PROGRESS);
1223        }
1224
1225#if (1 == BDMA_P_SHOW_SG_OPEN)
1226        if (bSgOpen)
1227        {
1228                BDBG_ERR(("!!!!!!!! Scatter-gather still open at end with Tran %d",
1229                                  pTran - pQueue->pHeadEntry));
1230        }
1231#endif
1232       
1233        /* put this Tran into sw queue */
1234        pTran->eStatus = BDMA_TranStatus_eInProgress;
1235        pTran->pNextTran = NULL; /* Proc*Status rely on this to get out of loop */
1236        pTran->ulNumActBlocks = ulNumActBlocks;
1237        pTran->pCallBackFunc_isr = pCallBackFunc_isr;           
1238        pTran->pUserCallBackParam = pUserCallBackParam;
1239        pQueue->bSgOpenInQ = bSgOpen;
1240        if (pQueue->pHeadTranInQ)
1241        {
1242                /* append this Tran into sw queue */
1243                (*pQueue->pAppendTranDesc_isr)(pQueue->pTailTranInQ, pTran);
1244                pQueue->pTailTranInQ->pNextTran = pTran;
1245        }
1246        else
1247        {
1248                pQueue->pHeadTranInQ = pTran;
1249        }
1250        pQueue->pTailTranInQ = pTran;
1251       
1252        /* check and try to setup the tran in hw */
1253        BDMA_P_Queue_CheckHwAndSendNewReq_isr(hQueue);
1254       
1255        return BERR_SUCCESS;
1256}
1257
1258/***************************************************************************
1259 * {private}
1260 * BDMA_P_Queue_DestroyTran_isr
1261 *
1262 * To be called to destroy a Tran. It reset the Tran's entries to make the
1263 * chunk of blocks as a destroyed Tran
1264 *
1265 * Note: assume parameters are valid
1266 */
1267BERR_Code BDMA_P_Queue_DestroyTran_isr
1268        ( BDMA_P_QueueHandle       hQueue,
1269          BDMA_P_QueueEntry *      pTran )
1270{
1271        BDMA_P_QueueContext * pQueue;
1272
1273        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
1274        BDBG_ASSERT( NULL != pQueue );
1275        BDBG_ASSERT( NULL != pTran );
1276        BDMA_P_QUEUE_ASSERT_UNCORRUPT( pQueue );
1277
1278        /* if pTran is pTailTranInHw in the case (true==pQueue->bSgOpenInHw),
1279         * we can not destroy it yet, it is needed for future desc link */
1280        if ( (BDMA_TranStatus_eInProgress != pTran->eStatus) &&
1281                 ((!pQueue->bSgOpenInHw) || (pTran != pQueue->pTailTranInHw)) )
1282        {
1283                /* reset the blocks in this Tran */
1284                BDMA_P_Queue_ReInitBlocks_isr( pQueue, pTran, pTran->ulNumTranBlocks );
1285                return BERR_SUCCESS;
1286        }
1287        else
1288        {
1289                BDBG_ERR(("destroy in prog tran at entry %d", pTran - pQueue->pHeadEntry));
1290                return BERR_TRACE(BDMA_ERR_TRAN_IN_PROGRESS);
1291        }
1292}
1293
1294/***************************************************************************
1295 * {private}
1296 * BDMA_P_Queue_ResetTran_isr
1297 *
1298 * To be called to reset a active Tran into intial eCreated state. Without
1299 * resetting, the Tran could also be used to SetBlockInfo and Start again,
1300 * but the module will not be able to check whether each block info is set.
1301 *
1302 * Note: assume parameters are valid,
1303 */
1304BERR_Code BDMA_P_Queue_ResetTran_isr
1305        ( BDMA_P_QueueHandle       hQueue,
1306          BDMA_P_QueueEntry *      pTran )
1307{
1308        BDMA_P_QueueContext * pQueue;
1309        uint32_t  ulNumTranBlocks;
1310        bool  bCachedDscrp;
1311
1312        BDMA_P_QUEUE_GET_CONTEXT( hQueue, pQueue );
1313        BDBG_ASSERT( NULL != pQueue );
1314        BDBG_ASSERT( NULL != pTran );
1315        BDMA_P_QUEUE_ASSERT_UNCORRUPT( pQueue );
1316
1317        if ( BDMA_TranStatus_eInProgress != pTran->eStatus )
1318        {
1319                bCachedDscrp = pTran->bCachedDscrp; /* save for restore back */
1320                ulNumTranBlocks = pTran->ulNumTranBlocks;
1321                BDMA_P_Queue_ReInitBlocks_isr( pQueue, pTran, pTran->ulNumTranBlocks );
1322                pTran->bCachedDscrp = bCachedDscrp; /* restore back  */
1323                pTran->ulNumTranBlocks = ulNumTranBlocks;
1324                pTran->eStatus = BDMA_TranStatus_eCreated;
1325                return BERR_SUCCESS;
1326        }
1327        else
1328        {
1329                return BERR_TRACE(BDMA_ERR_TRAN_IN_PROGRESS);
1330        }
1331}
1332
1333/* End of File */
Note: See TracBrowser for help on using the repository browser.