/** * \fn txnQ_SelectTxn * \brief Select transaction to send * * Called from txnQ_RunScheduler() which is protected in critical section. * Select the next enabled transaction by priority. * * \note * \param pTxnQ - The module's object * \return The selected transaction to send (NULL if none available) * \sa */ static TTxnStruct *txnQ_SelectTxn (TTxnQObj *pTxnQ) { TTxnStruct *pSelectedTxn; TI_UINT32 uFunc; TI_UINT32 uPrio; #ifdef TI_DBG /* If within Tx aggregation, dequeue Txn from same queue, and if not NULL return it */ if (pTxnQ->pAggregQueue) { pSelectedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->pAggregQueue); if (pSelectedTxn != NULL) { /* If aggregation ended, reset the aggregation-queue pointer */ if (TXN_PARAM_GET_AGGREGATE(pSelectedTxn) == TXN_AGGREGATE_OFF) { pTxnQ->pAggregQueue = NULL; } return pSelectedTxn; } return NULL; } #endif /* For all functions, if single-step Txn waiting, return it (sent even if function is stopped) */ for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++) { pSelectedTxn = pTxnQ->aFuncInfo[uFunc].pSingleStep; if (pSelectedTxn != NULL) { pTxnQ->aFuncInfo[uFunc].pSingleStep = NULL; return pSelectedTxn; } } /* For all priorities from high to low */ for (uPrio = 0; uPrio < MAX_PRIORITY; uPrio++) { /* For all functions */ for (uFunc = pTxnQ->uMinFuncId; uFunc <= pTxnQ->uMaxFuncId; uFunc++) { /* If function running and uses this priority */ if (pTxnQ->aFuncInfo[uFunc].eState == FUNC_STATE_RUNNING && pTxnQ->aFuncInfo[uFunc].uNumPrios > uPrio) { /* Dequeue Txn from current func and priority queue, and if not NULL return it */ pSelectedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFunc][uPrio]); if (pSelectedTxn != NULL) { #ifdef TI_DBG /* If aggregation begins, save the aggregation-queue pointer to ensure continuity */ if (TXN_PARAM_GET_AGGREGATE(pSelectedTxn) == TXN_AGGREGATE_ON) { pTxnQ->pAggregQueue = pTxnQ->aTxnQueues[uFunc][uPrio]; } #endif return pSelectedTxn; } } } } /* If no transaction was selected, return NULL */ return NULL; }
/** * \fn busDrv_PrepareTxnParts * \brief Prepare write or read transaction parts * * Called by busDrv_Transact(). * Prepares the actual sequence of SDIO bus transactions in a table. * Use a DMA-able buffer for the bus transaction, so all data is copied * to it from the host buffer(s) before write transactions, * or copied from it to the host buffers after read transactions. * * \note * \param pBusDrv - The module's object * \param pTxn - The transaction object * \return TRUE if we are in the middle of a Tx aggregation * \sa busDrv_Transact, busDrv_SendTxnParts, */ static TI_BOOL busDrv_PrepareTxnParts (TBusDrvObj *pBusDrv, TTxnStruct *pTxn) { TI_UINT32 uPartNum = 0; TI_UINT32 uCurrHwAddr = pTxn->uHwAddr; TI_BOOL bFixedHwAddr = TXN_PARAM_GET_FIXED_ADDR(pTxn); TI_BOOL bWrite = (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_WRITE) ? TI_TRUE : TI_FALSE; TI_UINT8 *pHostBuf = bWrite ? pBusDrv->pTxDmaBuf : pBusDrv->pRxDmaBuf; /* Use DMA buffer (Rx or Tx) for actual transaction */ TI_UINT32 uBufNum; TI_UINT32 uBufLen; TI_UINT32 uRemainderLen; /* Go over the transaction buffers */ for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++) { uBufLen = pTxn->aLen[uBufNum]; /* If no more buffers, exit the loop */ if (uBufLen == 0) { break; } /* For write transaction, copy the data to the DMA buffer */ if (bWrite) { os_memoryCopy (pBusDrv->hOs, pHostBuf + pBusDrv->uTxnLength, pTxn->aBuf[uBufNum], uBufLen); } /* Add buffer length to total transaction length */ pBusDrv->uTxnLength += uBufLen; } /* If in a Tx aggregation, return TRUE (need to accumulate all parts before sending the transaction) */ if (TXN_PARAM_GET_AGGREGATE(pTxn) == TXN_AGGREGATE_ON) { 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]); return TI_TRUE; } /* If current buffer has a remainder, prepare its transaction part */ uRemainderLen = pBusDrv->uTxnLength & pBusDrv->uBlkSizeMask; if (uRemainderLen > 0) { pBusDrv->aTxnParts[uPartNum].bBlkMode = TI_FALSE; pBusDrv->aTxnParts[uPartNum].uLength = uRemainderLen; pBusDrv->aTxnParts[uPartNum].uHwAddr = uCurrHwAddr; pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)pHostBuf; pBusDrv->aTxnParts[uPartNum].bMore = TI_TRUE; /* If not fixed HW address, increment it by this part's size */ if (!bFixedHwAddr) { uCurrHwAddr += uRemainderLen; } uPartNum++; } #ifdef DISABLE_SDIO_MULTI_BLK_MODE /* SDIO multi-block mode is disabled so split to 512 bytes blocks */ { TI_UINT32 uLen; for (uLen = uRemainderLen; uLen < pBusDrv->uTxnLength; uLen += pBusDrv->uBlkSize) { pBusDrv->aTxnParts[uPartNum].bBlkMode = TI_FALSE; pBusDrv->aTxnParts[uPartNum].uLength = pBusDrv->uBlkSize; pBusDrv->aTxnParts[uPartNum].uHwAddr = uCurrHwAddr; pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pHostBuf + uLen); pBusDrv->aTxnParts[uPartNum].bMore = TI_TRUE; /* If not fixed HW address, increment it by this part's size */ if (!bFixedHwAddr) { uCurrHwAddr += pBusDrv->uBlkSize; } uPartNum++; } } #else /* Use SDIO block mode (this is the default behavior) */ /* If current buffer has full SDIO blocks, prepare a block-mode transaction part */ if (pBusDrv->uTxnLength >= pBusDrv->uBlkSize) { pBusDrv->aTxnParts[uPartNum].bBlkMode = TI_TRUE; pBusDrv->aTxnParts[uPartNum].uLength = pBusDrv->uTxnLength - uRemainderLen; pBusDrv->aTxnParts[uPartNum].uHwAddr = uCurrHwAddr; pBusDrv->aTxnParts[uPartNum].pHostAddr = (void *)(pHostBuf + uRemainderLen); pBusDrv->aTxnParts[uPartNum].bMore = TI_TRUE; uPartNum++; } #endif /* DISABLE_SDIO_MULTI_BLK_MODE */ /* Set last More flag as specified for the whole Txn */ pBusDrv->aTxnParts[uPartNum - 1].bMore = TXN_PARAM_GET_MORE(pTxn); pBusDrv->uCurrTxnPartsNum = uPartNum; 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]); pBusDrv->uTxnLength = 0; /* Return FALSE to indicate that we are not in the middle of a Tx aggregation so the Txn is ready to send */ return TI_FALSE; }