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