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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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