• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * SdioBusDrv.c
3  *
4  * Copyright(c) 1998 - 2010 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 /** \file   SdioBusDrv.c
36  *  \brief  The SDIO bus driver upper layer. Platform independent.
37  *          Uses the SdioAdapter API.
38  *          Introduces a generic bus-independent API upwards.
39  *
40  *  \see    BusDrv.h, SdioAdapter.h, SdioAdapter.c
41  */
42 
43 #define __FILE_ID__  FILE_ID_122
44 #include "tidef.h"
45 #include "report.h"
46 #include "osApi.h"
47 #include "TxnDefs.h"
48 #include "SdioAdapter.h"
49 #include "BusDrv.h"
50 #include "bmtrace_api.h"
51 
52 
53 
54 /************************************************************************
55  * Defines
56  ************************************************************************/
57 #define MAX_TXN_PARTS     MAX_XFER_BUFS * 5   /* for aggregation we may need a few parts for each buffer */
58 
59 
60 /************************************************************************
61  * Types
62  ************************************************************************/
63 
64 /* A single SDIO bus transaction which is a part of a complete transaction (TTxnStruct) */
65 typedef struct
66 {
67     TI_BOOL          bBlkMode;           /* If TRUE this is a block-mode SDIO transaction */
68     TI_UINT32        uLength;            /* Length in byte */
69     TI_UINT32        uHwAddr;            /* The device address to write to or read from */
70     void *           pHostAddr;          /* The host buffer address to write from or read into */
71     TI_BOOL          bMore;              /* If TRUE, indicates the lower driver to keep awake for more transactions */
72 } TTxnPart;
73 
74 
75 /* The busDrv module Object */
76 typedef struct _TBusDrvObj
77 {
78     TI_HANDLE	     hOs;
79     TI_HANDLE	     hReport;
80 
81 	TBusDrvTxnDoneCb fTxnDoneCb;         /* The callback to call upon full transaction completion. */
82 	TI_HANDLE        hCbHandle;          /* The callback handle */
83     TTxnStruct *     pCurrTxn;           /* The transaction currently being processed */
84     ETxnStatus       eCurrTxnStatus;     /* COMPLETE, PENDING or ERROR */
85     TTxnPart         aTxnParts[MAX_TXN_PARTS]; /* The actual bus transactions of current transaction */
86     TI_UINT32        uCurrTxnPartsNum;   /* Number of transaction parts composing the current transaction */
87     TI_UINT32        uCurrTxnPartsCount; /* Number of transaction parts already executed */
88     TI_UINT32        uCurrTxnPartsCountSync; /* Number of transaction parts completed in Sync mode (returned COMPLETE) */
89     TI_UINT32        uBlkSizeShift;      /* In block-mode:  uBlkSize = (1 << uBlkSizeShift) = 512 bytes */
90     TI_UINT32        uBlkSize;           /* In block-mode:  uBlkSize = (1 << uBlkSizeShift) = 512 bytes */
91     TI_UINT32        uBlkSizeMask;       /* In block-mode:  uBlkSizeMask = uBlkSize - 1 = 0x1FF*/
92     TI_UINT8 *       pRxDmaBuf;          /* The Rx DMA-able buffer for buffering all write transactions */
93     TI_UINT32        uRxDmaBufLen;       /* The Rx DMA-able buffer length in bytes */
94     TI_UINT8 *       pTxDmaBuf;          /* The Tx DMA-able buffer for buffering all write transactions */
95     TI_UINT32        uTxDmaBufLen;       /* The Tx DMA-able buffer length in bytes */
96     TI_UINT32        uTxnLength;         /* The current transaction accumulated length (including Tx aggregation case) */
97 
98 } TBusDrvObj;
99 
100 
101 /************************************************************************
102  * Internal functions prototypes
103  ************************************************************************/
104 static TI_BOOL  busDrv_PrepareTxnParts  (TBusDrvObj *pBusDrv, TTxnStruct *pTxn);
105 static void     busDrv_SendTxnParts     (TBusDrvObj *pBusDrv);
106 static void     busDrv_TxnDoneCb        (TI_HANDLE hBusDrv, TI_INT32 status);
107 
108 
109 
110 /************************************************************************
111  *
112  *   Module functions implementation
113  *
114  ************************************************************************/
115 
116 /**
117  * \fn     busDrv_Create
118  * \brief  Create the module
119  *
120  * Create and clear the bus driver's object, and the SDIO-adapter.
121  *
122  * \note
123  * \param  hOs - Handle to Os Abstraction Layer
124  * \return Handle of the allocated object, NULL if allocation failed
125  * \sa     busDrv_Destroy
126  */
busDrv_Create(TI_HANDLE hOs)127 TI_HANDLE busDrv_Create (TI_HANDLE hOs)
128 {
129     TI_HANDLE   hBusDrv;
130     TBusDrvObj *pBusDrv;
131 
132     hBusDrv = os_memoryAlloc(hOs, sizeof(TBusDrvObj));
133     if (hBusDrv == NULL)
134     {
135         return NULL;
136     }
137 
138     pBusDrv = (TBusDrvObj *)hBusDrv;
139 
140     os_memoryZero(hOs, hBusDrv, sizeof(TBusDrvObj));
141 
142     pBusDrv->hOs = hOs;
143 
144     return pBusDrv;
145 }
146 
147 
148 /**
149  * \fn     busDrv_Destroy
150  * \brief  Destroy the module.
151  *
152  * Close SDIO lower bus driver and free the module's object.
153  *
154  * \note
155  * \param  The module's object
156  * \return TI_OK on success or TI_NOK on failure
157  * \sa     busDrv_Create
158  */
busDrv_Destroy(TI_HANDLE hBusDrv)159 TI_STATUS busDrv_Destroy (TI_HANDLE hBusDrv)
160 {
161     TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
162 
163     if (pBusDrv)
164     {
165         os_memoryFree (pBusDrv->hOs, pBusDrv, sizeof(TBusDrvObj));
166     }
167     return TI_OK;
168 }
169 
170 
171 /**
172  * \fn     busDrv_Init
173  * \brief  Init bus driver
174  *
175  * Init module parameters.
176 
177  * \note
178  * \param  hBusDrv - The module's handle
179  * \param  hReport - report module handle
180  * \return void
181  * \sa
182  */
busDrv_Init(TI_HANDLE hBusDrv,TI_HANDLE hReport)183 void busDrv_Init (TI_HANDLE hBusDrv, TI_HANDLE hReport)
184 {
185     TBusDrvObj *pBusDrv = (TBusDrvObj*) hBusDrv;
186 
187     pBusDrv->hReport = hReport;
188 }
189 
190 
191 /**
192  * \fn     busDrv_ConnectBus
193  * \brief  Configure bus driver
194  *
195  * Called by TxnQ.
196  * Configure the bus driver with its connection configuration (such as baud-rate, bus width etc)
197  *     and establish the physical connection.
198  * Done once upon init (and not per functional driver startup).
199  *
200  * \note
201  * \param  hBusDrv    - The module's object
202  * \param  pBusDrvCfg - A union used for per-bus specific configuration.
203  * \param  fCbFunc    - CB function for Async transaction completion (after all txn parts are completed).
204  * \param  hCbArg     - The CB function handle
205  * \param  fConnectCbFunc - The CB function for the connect bus competion (if returned Pending)
206  * \param  pRxDmaBufLen - The Rx DMA buffer length in bytes (needed as a limit of the Tx/Rx aggregation length)
207  * \param  pTxDmaBufLen - The Tx DMA buffer length in bytes (needed as a limit of the Tx/Rx aggregation length)
208  * \return TI_OK / TI_NOK
209  * \sa
210  */
busDrv_ConnectBus(TI_HANDLE hBusDrv,TBusDrvCfg * pBusDrvCfg,TBusDrvTxnDoneCb fCbFunc,TI_HANDLE hCbArg,TBusDrvTxnDoneCb fConnectCbFunc,TI_UINT32 * pRxDmaBufLen,TI_UINT32 * pTxDmaBufLen)211 TI_STATUS busDrv_ConnectBus (TI_HANDLE        hBusDrv,
212                              TBusDrvCfg       *pBusDrvCfg,
213                              TBusDrvTxnDoneCb fCbFunc,
214                              TI_HANDLE        hCbArg,
215                              TBusDrvTxnDoneCb fConnectCbFunc,
216                              TI_UINT32        *pRxDmaBufLen,
217                              TI_UINT32        *pTxDmaBufLen)
218 {
219     TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
220     int         iStatus;
221 
222     /* Save the parameters (TxnQ callback for TxnDone events, and block-size) */
223     pBusDrv->fTxnDoneCb    = fCbFunc;
224     pBusDrv->hCbHandle     = hCbArg;
225     pBusDrv->uBlkSizeShift = pBusDrvCfg->tSdioCfg.uBlkSizeShift;
226     pBusDrv->uBlkSize      = 1 << pBusDrv->uBlkSizeShift;
227     pBusDrv->uBlkSizeMask  = pBusDrv->uBlkSize - 1;
228     /* This should cover stop send Txn parts in recovery */
229     pBusDrv->uCurrTxnPartsCount = 0;
230     pBusDrv->uCurrTxnPartsNum = 0;
231     pBusDrv->uCurrTxnPartsCountSync = 0;
232     pBusDrv->uTxnLength = 0;
233 
234     /*
235      * Configure the SDIO driver parameters and handle SDIO enumeration.
236      *
237      * Note: The DMA-able buffer address to use for write transactions is provided from the
238      *           SDIO driver into pBusDrv->pDmaBuffer.
239      */
240 
241     iStatus = sdioAdapt_ConnectBus ((void *)busDrv_TxnDoneCb,
242                                     hBusDrv,
243                                     pBusDrv->uBlkSizeShift,
244                                     pBusDrvCfg->tSdioCfg.uBusDrvThreadPriority,
245                                     &pBusDrv->pRxDmaBuf,
246                                     &pBusDrv->uRxDmaBufLen,
247                                     &pBusDrv->pTxDmaBuf,
248                                     &pBusDrv->uTxDmaBufLen);
249 
250     *pRxDmaBufLen = pBusDrv->uRxDmaBufLen;
251     *pTxDmaBufLen = pBusDrv->uTxDmaBufLen;
252 
253     if ((pBusDrv->pRxDmaBuf == NULL) || (pBusDrv->pTxDmaBuf == NULL))
254     {
255         TRACE0(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_ConnectBus: Didn't get DMA buffer from SDIO driver!!");
256         return TI_NOK;
257     }
258 
259     if (iStatus == 0)
260     {
261         return TI_OK;
262     }
263     else
264     {
265         TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_ConnectBus: Status = 0x%x, BlkSize = %d\n", iStatus, pBusDrv->uBlkSize);
266         return TI_NOK;
267     }
268 }
269 
270 
271 /**
272  * \fn     busDrv_DisconnectBus
273  * \brief  Disconnect SDIO driver
274  *
275  * Called by TxnQ. Disconnect the SDIO driver.
276  *
277  * \note
278  * \param  hBusDrv - The module's object
279  * \return TI_OK / TI_NOK
280  * \sa
281  */
busDrv_DisconnectBus(TI_HANDLE hBusDrv)282 TI_STATUS busDrv_DisconnectBus (TI_HANDLE hBusDrv)
283 {
284     TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
285 
286     TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_DisconnectBus()\n");
287 
288     /* Disconnect SDIO driver */
289     return sdioAdapt_DisconnectBus ();
290 }
291 
292 
293 /**
294  * \fn     busDrv_Transact
295  * \brief  Process transaction
296  *
297  * Called by the TxnQ module to initiate a new transaction.
298  * Prepare the transaction parts (lower layer single transactions),
299  *      and send them one by one to the lower layer.
300  *
301  * \note   It's assumed that this function is called only when idle (i.e. previous Txn is done).
302  * \param  hBusDrv - The module's object
303  * \param  pTxn    - The transaction object
304  * \return COMPLETE if Txn completed in this context, PENDING if not, ERROR if failed
305  * \sa     busDrv_PrepareTxnParts, busDrv_SendTxnParts
306  */
busDrv_Transact(TI_HANDLE hBusDrv,TTxnStruct * pTxn)307 ETxnStatus busDrv_Transact (TI_HANDLE hBusDrv, TTxnStruct *pTxn)
308 {
309     TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
310     TI_BOOL     bWithinAggregation;
311     CL_TRACE_START_L4();
312 
313     pBusDrv->pCurrTxn               = pTxn;
314     pBusDrv->uCurrTxnPartsCount     = 0;
315     pBusDrv->uCurrTxnPartsCountSync = 0;
316 
317     /* Prepare the transaction parts in a table. */
318     bWithinAggregation = busDrv_PrepareTxnParts (pBusDrv, pTxn);
319 
320     /* If in the middle of Tx aggregation, return Complete (current Txn was coppied to buffer but not sent) */
321     if (bWithinAggregation)
322     {
323         TRACE1(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_Transact: In aggregation so exit, uTxnLength=%d\n", pBusDrv->uTxnLength);
324         CL_TRACE_END_L4("tiwlan_drv.ko", "INHERIT", "TXN", ".Transact");
325         return TXN_STATUS_COMPLETE;
326     }
327 
328     /* Send the prepared transaction parts. */
329     busDrv_SendTxnParts (pBusDrv);
330 
331     TRACE1(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_Transact: Status = %d\n", pBusDrv->eCurrTxnStatus);
332 
333     CL_TRACE_END_L4("tiwlan_drv.ko", "INHERIT", "TXN", ".Transact");
334 
335     /* return transaction status - COMPLETE, PENDING or ERROR */
336     /* The status is updated in busDrv_SendTxnParts(). It is Async (pending) if not completed in this context */
337     return pBusDrv->eCurrTxnStatus;
338 }
339 
340 
341 /**
342  * \fn     busDrv_PrepareTxnParts
343  * \brief  Prepare write or read transaction parts
344  *
345  * Called by busDrv_Transact().
346  * Prepares the actual sequence of SDIO bus transactions in a table.
347  * Use a DMA-able buffer for the bus transaction, so all data is copied
348  *     to it from the host buffer(s) before write transactions,
349  *     or copied from it to the host buffers after read transactions.
350  *
351  * \note
352  * \param  pBusDrv - The module's object
353  * \param  pTxn    - The transaction object
354  * \return TRUE if we are in the middle of a Tx aggregation
355  * \sa     busDrv_Transact, busDrv_SendTxnParts,
356  */
busDrv_PrepareTxnParts(TBusDrvObj * pBusDrv,TTxnStruct * pTxn)357 static TI_BOOL busDrv_PrepareTxnParts (TBusDrvObj *pBusDrv, TTxnStruct *pTxn)
358 {
359     TI_UINT32 uPartNum     = 0;
360     TI_UINT32 uCurrHwAddr  = pTxn->uHwAddr;
361     TI_BOOL   bFixedHwAddr = TXN_PARAM_GET_FIXED_ADDR(pTxn);
362     TI_BOOL   bWrite       = (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_WRITE) ? TI_TRUE : TI_FALSE;
363     TI_UINT8 *pHostBuf     = bWrite ? pBusDrv->pTxDmaBuf : pBusDrv->pRxDmaBuf; /* Use DMA buffer (Rx or Tx) for actual transaction */
364     TI_UINT32 uBufNum;
365     TI_UINT32 uBufLen;
366     TI_UINT32 uRemainderLen;
367 
368     /* Go over the transaction buffers */
369     for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++)
370     {
371         uBufLen = pTxn->aLen[uBufNum];
372 
373         /* If no more buffers, exit the loop */
374         if (uBufLen == 0)
375         {
376             break;
377         }
378 
379         /* For write transaction, copy the data to the DMA buffer */
380         if (bWrite)
381         {
382             os_memoryCopy (pBusDrv->hOs, pHostBuf + pBusDrv->uTxnLength, pTxn->aBuf[uBufNum], uBufLen);
383         }
384 
385         /* Add buffer length to total transaction length */
386         pBusDrv->uTxnLength += uBufLen;
387     }
388 
389     /* If in a Tx aggregation, return TRUE (need to accumulate all parts before sending the transaction) */
390     if (TXN_PARAM_GET_AGGREGATE(pTxn) == TXN_AGGREGATE_ON)
391     {
392         TRACE6(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_PrepareTxnParts: In aggregation so exit, uTxnLength=%d, bWrite=%d, Len0=%d, Len1=%d, Len2=%d, Len3=%d\n", pBusDrv->uTxnLength, bWrite, pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3]);
393         return TI_TRUE;
394     }
395 
396     /* If current buffer has a remainder, prepare its transaction part */
397     uRemainderLen = pBusDrv->uTxnLength & pBusDrv->uBlkSizeMask;
398     if (uRemainderLen > 0)
399     {
400         pBusDrv->aTxnParts[uPartNum].bBlkMode  = TI_FALSE;
401         pBusDrv->aTxnParts[uPartNum].uLength   = uRemainderLen;
402         pBusDrv->aTxnParts[uPartNum].uHwAddr   = uCurrHwAddr;
403         pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)pHostBuf;
404         pBusDrv->aTxnParts[uPartNum].bMore     = TI_TRUE;
405 
406         /* If not fixed HW address, increment it by this part's size */
407         if (!bFixedHwAddr)
408         {
409             uCurrHwAddr += uRemainderLen;
410         }
411 
412         uPartNum++;
413     }
414 
415 #ifdef  DISABLE_SDIO_MULTI_BLK_MODE
416 
417     /* SDIO multi-block mode is disabled so split to 512 bytes blocks */
418     {
419         TI_UINT32 uLen;
420 
421         for (uLen = uRemainderLen; uLen < pBusDrv->uTxnLength; uLen += pBusDrv->uBlkSize)
422         {
423             pBusDrv->aTxnParts[uPartNum].bBlkMode  = TI_FALSE;
424             pBusDrv->aTxnParts[uPartNum].uLength   = pBusDrv->uBlkSize;
425             pBusDrv->aTxnParts[uPartNum].uHwAddr   = uCurrHwAddr;
426             pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pHostBuf + uLen);
427             pBusDrv->aTxnParts[uPartNum].bMore     = TI_TRUE;
428 
429             /* If not fixed HW address, increment it by this part's size */
430             if (!bFixedHwAddr)
431             {
432                 uCurrHwAddr += pBusDrv->uBlkSize;
433             }
434 
435             uPartNum++;
436         }
437     }
438 
439 #else  /* Use SDIO block mode (this is the default behavior) */
440 
441     /* If current buffer has full SDIO blocks, prepare a block-mode transaction part */
442     if (pBusDrv->uTxnLength >= pBusDrv->uBlkSize)
443     {
444         pBusDrv->aTxnParts[uPartNum].bBlkMode  = TI_TRUE;
445         pBusDrv->aTxnParts[uPartNum].uLength   = pBusDrv->uTxnLength - uRemainderLen;
446         pBusDrv->aTxnParts[uPartNum].uHwAddr   = uCurrHwAddr;
447         pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pHostBuf + uRemainderLen);
448         pBusDrv->aTxnParts[uPartNum].bMore     = TI_TRUE;
449 
450         uPartNum++;
451     }
452 
453 #endif /* DISABLE_SDIO_MULTI_BLK_MODE */
454 
455     /* Set last More flag as specified for the whole Txn */
456     pBusDrv->aTxnParts[uPartNum - 1].bMore = TXN_PARAM_GET_MORE(pTxn);
457     pBusDrv->uCurrTxnPartsNum = uPartNum;
458 
459     TRACE9(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_PrepareTxnParts: Txn prepared, PartsNum=%d, bWrite=%d, uTxnLength=%d, uRemainderLen=%d, uHwAddr=0x%x, Len0=%d, Len1=%d, Len2=%d, Len3=%d\n", uPartNum, bWrite, pBusDrv->uTxnLength, uRemainderLen, pTxn->uHwAddr, pTxn->aLen[0], pTxn->aLen[1], pTxn->aLen[2], pTxn->aLen[3]);
460 
461     pBusDrv->uTxnLength = 0;
462 
463     /* Return FALSE to indicate that we are not in the middle of a Tx aggregation so the Txn is ready to send */
464     return TI_FALSE;
465 }
466 
467 
468 /**
469  * \fn     busDrv_SendTxnParts
470  * \brief  Send prepared transaction parts
471  *
472  * Called first by busDrv_Transact(), and also from TxnDone CB after Async completion.
473  * Sends the prepared transaction parts in a loop.
474  * If a transaction part is Async, the loop continues later in the TxnDone ISR context.
475  * When all parts are done, the upper layer TxnDone CB is called.
476  *
477  * \note
478  * \param  pBusDrv - The module's object
479  * \return void
480  * \sa     busDrv_Transact, busDrv_PrepareTxnParts
481  */
busDrv_SendTxnParts(TBusDrvObj * pBusDrv)482 static void busDrv_SendTxnParts (TBusDrvObj *pBusDrv)
483 {
484     ETxnStatus  eStatus;
485     TTxnPart   *pTxnPart;
486     TTxnStruct *pTxn = pBusDrv->pCurrTxn;
487 
488     /* While there are transaction parts to send */
489     while (pBusDrv->uCurrTxnPartsCount < pBusDrv->uCurrTxnPartsNum)
490     {
491         pTxnPart = &(pBusDrv->aTxnParts[pBusDrv->uCurrTxnPartsCount]);
492         pBusDrv->uCurrTxnPartsCount++;
493 
494         /* Assume pending to be ready in case we are preempted by the TxnDon CB !! */
495         pBusDrv->eCurrTxnStatus = TXN_STATUS_PENDING;
496 
497         /* If single step, send ELP byte */
498         if (TXN_PARAM_GET_SINGLE_STEP(pTxn))
499         {
500             /* Overwrite the function id with function 0 - for ELP register !!!! */
501             eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL,
502                                                pTxnPart->uHwAddr,
503                                                pTxnPart->pHostAddr,
504                                                pTxnPart->uLength,
505                                                TXN_PARAM_GET_DIRECTION(pTxn),
506                                                pTxnPart->bMore);
507 
508             /* If first write failed try once again (may happen once upon chip wakeup) */
509             if (eStatus == TXN_STATUS_ERROR)
510             {
511                 /* Overwrite the function id with function 0 - for ELP register !!!! */
512                 eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL,
513                                                    pTxnPart->uHwAddr,
514                                                    pTxnPart->pHostAddr,
515                                                    pTxnPart->uLength,
516                                                    TXN_PARAM_GET_DIRECTION(pTxn),
517                                                    pTxnPart->bMore);
518                 TRACE0(pBusDrv->hReport, REPORT_SEVERITY_WARNING, "busDrv_SendTxnParts: SDIO Single-Step transaction failed once so try again");
519             }
520         }
521         else
522         {
523             eStatus = sdioAdapt_Transact (TXN_PARAM_GET_FUNC_ID(pTxn),
524                                           pTxnPart->uHwAddr,
525                                           pTxnPart->pHostAddr,
526                                           pTxnPart->uLength,
527                                           TXN_PARAM_GET_DIRECTION(pTxn),
528                                           pTxnPart->bBlkMode,
529                                           ((TXN_PARAM_GET_FIXED_ADDR(pTxn) == 1) ? 0 : 1),
530                                           pTxnPart->bMore);
531         }
532 
533         TRACE7(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: PartNum = %d, SingleStep = %d, Direction = %d, HwAddr = 0x%x, HostAddr = 0x%x, Length = %d, BlkMode = %d\n", pBusDrv->uCurrTxnPartsCount-1, TXN_PARAM_GET_SINGLE_STEP(pTxn), TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, pTxnPart->bBlkMode);
534 
535         /* If pending TxnDone (Async), continue this loop in the next TxnDone interrupt */
536         if (eStatus == TXN_STATUS_PENDING)
537         {
538             return;
539         }
540 
541         /* Update current transaction status to deduce if it is all finished in the original context (Sync) or not. */
542         pBusDrv->eCurrTxnStatus = eStatus;
543         pBusDrv->uCurrTxnPartsCountSync++;
544 
545         /* If error, set error in Txn struct, call TxnDone CB if not fully sync, and exit */
546         if (eStatus == TXN_STATUS_ERROR)
547         {
548             TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_ERROR);
549             if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount)
550             {
551                 pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn);
552             }
553         	return;
554         }
555     }
556 
557     /* If we got here we sent all buffers and we don't pend transaction end */
558     TRACE3(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: Txn finished successfully, Status = %d, PartsCount = %d, SyncCount = %d\n", pBusDrv->eCurrTxnStatus, pBusDrv->uCurrTxnPartsCount, pBusDrv->uCurrTxnPartsCountSync);
559 
560     /* For read transaction, copy the data from the DMA-able buffer to the host buffer(s) */
561     if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_READ)
562     {
563         TI_UINT32 uBufNum;
564         TI_UINT32 uBufLen;
565         TI_UINT8 *pDmaBuf = pBusDrv->pRxDmaBuf; /* After the read transaction the data is in the Rx DMA buffer */
566 
567         for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++)
568         {
569             uBufLen = pTxn->aLen[uBufNum];
570 
571             /* If no more buffers, exit the loop */
572             if (uBufLen == 0)
573             {
574                 break;
575             }
576 
577             os_memoryCopy (pBusDrv->hOs, pTxn->aBuf[uBufNum], pDmaBuf, uBufLen);
578             pDmaBuf += uBufLen;
579         }
580     }
581 
582     /* Set status OK in Txn struct, and call TxnDone CB if not fully sync */
583     TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_OK);
584     if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount)
585     {
586         pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn);
587     }
588 }
589 
590 
591 /**
592  * \fn     busDrv_TxnDoneCb
593  * \brief  Continue async transaction processing (CB)
594  *
595  * Called back by the lower (BSP) bus-driver upon Async transaction completion (TxnDone ISR).
596  * Call busDrv_SendTxnParts to continue sending the remained transaction parts.
597  *
598  * \note
599  * \param  hBusDrv - The module's object
600  * \param  status  - The last transaction result - 0 = OK, else Error
601  * \return void
602  * \sa     busDrv_SendTxnParts
603  */
busDrv_TxnDoneCb(TI_HANDLE hBusDrv,int iStatus)604 static void busDrv_TxnDoneCb (TI_HANDLE hBusDrv, int iStatus)
605 {
606     TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
607     CL_TRACE_START_L1();
608 
609     /* If last transaction part failed, set error in Txn struct, call TxnDone CB and exit. */
610     if (iStatus != 0)
611     {
612         TRACE1(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_TxnDoneCb: Status = 0x%x\n", iStatus);
613 
614         TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR);
615         pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pBusDrv->pCurrTxn);
616         CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", "");
617         return;
618     }
619 
620     TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_TxnDoneCb()\n");
621 
622     /* Continue sending the remained transaction parts. */
623     busDrv_SendTxnParts (pBusDrv);
624 
625     CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", "");
626 }
627