ETxnStatus txnQ_Transact (TI_HANDLE hTxnQ, TTxnStruct *pTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); ETxnStatus rc; if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { pTxnQ->aFuncInfo[uFuncId].pSingleStep = pTxn; TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Transact(): Single step Txn\n"); } else { TI_STATUS eStatus; TI_HANDLE hQueue = pTxnQ->aTxnQueues[uFuncId][TXN_PARAM_GET_PRIORITY(pTxn)]; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (hQueue, (TI_HANDLE)pTxn); context_LeaveCriticalSection (pTxnQ->hContext); if (eStatus != TI_OK) { TRACE3(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_Transact(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pTxn, pTxn->uHwAddr, pTxn->aLen[0]); return TXN_STATUS_ERROR; } TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Transact(): Regular Txn\n"); } /* Send queued transactions as possible */ rc = txnQ_RunScheduler (pTxnQ, pTxn); return rc; }
/** * \fn txnQ_TxnDoneCb * \brief Pending Transaction completion CB * * Called back by bus-driver upon pending transaction completion in TxnDone context (external!). * Enqueue completed transaction in TxnDone queue and call scheduler to send queued transactions. * * \note * \param hTxnQ - The module's object * \param pTxn - The completed transaction object * \return void * \sa */ static void txnQ_TxnDoneCb (TI_HANDLE hTxnQ, void *hTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TTxnStruct *pTxn = (TTxnStruct *)hTxn; TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); /* If the function of the completed Txn is waiting for restart */ if (pTxnQ->aFuncInfo[uFuncId].eState == FUNC_STATE_RESTART) { /* First, Clear the restarted function queues */ txnQ_ClearQueues (hTxnQ, uFuncId); /* Call function CB for current Txn with restart indication */ TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_RECOVERY); pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb (pTxnQ->aFuncInfo[uFuncId].hCbHandle, pTxn); } /* In the normal case (no restart), enqueue completed transaction in TxnDone queue */ else { TI_STATUS eStatus; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pTxn); context_LeaveCriticalSection (pTxnQ->hContext); } /* Indicate that no transaction is currently processed in the bus-driver */ pTxnQ->pCurrTxn = NULL; /* Send queued transactions as possible (TRUE indicates we are in external context) */ txnQ_RunScheduler (pTxnQ, NULL); }
ETxnStatus txnQ_Restart (TI_HANDLE hTxnQ, TI_UINT32 uFuncId) { TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Restart()\n"); context_EnterCriticalSection (pTxnQ->hContext); /* If a Txn from the calling function is in progress, set state to RESTART return PENDING */ if (pTxnQ->pCurrTxn) { if (TXN_PARAM_GET_FUNC_ID(pTxnQ->pCurrTxn) == uFuncId) { pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RESTART; context_LeaveCriticalSection (pTxnQ->hContext); TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Restart(): pCurrTxn pending\n"); /* Return PENDING to indicate that the restart will be completed later (in TxnDone) */ return TXN_STATUS_PENDING; } } context_LeaveCriticalSection (pTxnQ->hContext); /* Clear the calling function's queues (call function CB with status=RECOVERY) */ txnQ_ClearQueues (hTxnQ, uFuncId); /* Return COMPLETE to indicate that the restart was completed */ return TXN_STATUS_COMPLETE; }
/** * \fn txnQ_Transact * \brief Issue a new transaction * * Called by the functional driver to initiate a new transaction. * In critical section save transaction and call scheduler. * * \note * \param hTxnQ - The module's object * \param pTxn - The transaction object * \return COMPLETE if input pTxn completed in this context, PENDING if not, ERROR if failed * \sa */ ETxnStatus txnQ_Transact (handle_t hTxnQ, TTxnStruct *pTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; McpU32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); ETxnStatus rc; MCPF_ENTER_CRIT_SEC (pTxnQ->hMcpf); if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { pTxnQ->aFuncInfo[uFuncId].pSingleStep = pTxn; } else { handle_t hQueue = pTxnQ->aTxnQueues[uFuncId][TXN_PARAM_GET_PRIORITY(pTxn)]; que_Enqueue (hQueue, (handle_t)pTxn); } /* Send queued transactions as possible */ rc = txnQ_RunScheduler (pTxnQ, pTxn, MCP_FALSE); MCPF_EXIT_CRIT_SEC (pTxnQ->hMcpf); return rc; }
/** * \fn txnQ_TxnDoneCb * \brief Pending Transaction completion CB * * Called back by bus-driver upon pending transaction completion in TxnDone context (external!). * Enqueue completed transaction in TxnDone queue and call scheduler to send queued transactions. * * \note * \param hTxnQ - The module's object * \param pTxn - The completed transaction object * \return void * \sa */ static void txnQ_TxnDoneCb (handle_t hTxnQ, void *hTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TTxnStruct *pTxn = (TTxnStruct *)hTxn; McpU32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); #ifdef TRAN_DBG if (pTxn != pTxnQ->pCurrTxn) { MCPF_REPORT_ERROR(pTxnQ->hMcpf, QUEUE_MODULE_LOG, ("%s: CB returned pTxn 0x%p while pCurrTxn is 0x%p !!\n", __FUNCTION__, pTxn, pTxnQ->pCurrTxn)); } #endif /* Enter critical section if configured to do so */ if (pTxnQ->bProtectTxnDone) { MCPF_ENTER_CRIT_SEC (pTxnQ->hMcpf); } /* If the function of the completed Txn is waiting for restart */ if (pTxnQ->aFuncInfo[uFuncId].eState == FUNC_STATE_RESTART) { /* Call function CB for current Txn with recovery indication */ TXN_PARAM_SET_STATUS(pTxn, TXN_STATUS_RECOVERY); pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb (pTxnQ->aFuncInfo[uFuncId].hCbHandle, pTxn, MCP_TRUE); /* Clear the restarted function queues (call function CB with status=RECOVERY) */ txnQ_ClearQueues (pTxnQ, uFuncId, MCP_TRUE); } /* In the normal case (no restart), enqueue completed transaction in TxnDone queue */ else { que_Enqueue (pTxnQ->hTxnDoneQueue, (handle_t)pTxn); } /* Indicate that no transaction is currently processed in the bus-driver */ pTxnQ->pCurrTxn = NULL; /* Send queued transactions as possible (TRUE indicates we are in external context) */ txnQ_RunScheduler (pTxnQ, NULL, MCP_TRUE); /* Leave critical section if configured to do so */ if (pTxnQ->bProtectTxnDone) { MCPF_EXIT_CRIT_SEC (pTxnQ->hMcpf); } }
/** * \fn txnQ_TxnDoneCb * \brief Pending Transaction completion CB * * Called back by bus-driver upon pending transaction completion in TxnDone context (external!). * Enqueue completed transaction in TxnDone queue and call scheduler to send queued transactions. * * \note * \param hTxnQ - The module's object * \param pTxn - The completed transaction object * \return void * \sa */ static void txnQ_TxnDoneCb (TI_HANDLE hTxnQ, void *hTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TTxnStruct *pTxn = (TTxnStruct *)hTxn; TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); #ifdef TI_DBG TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_TxnDoneCb()\n"); if (pTxn != pTxnQ->pCurrTxn) { TRACE2(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_TxnDoneCb(): CB returned pTxn 0x%x while pCurrTxn is 0x%x !!\n", pTxn, pTxnQ->pCurrTxn); } #endif /* If the function of the completed Txn is waiting for restart */ if (pTxnQ->aFuncInfo[uFuncId].eState == FUNC_STATE_RESTART) { TRACE0(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_TxnDoneCb(): Handling restart\n"); /* First, Clear the restarted function queues */ txnQ_ClearQueues (hTxnQ, uFuncId); /* Call function CB for current Txn with restart indication */ TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_RECOVERY); pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb (pTxnQ->aFuncInfo[uFuncId].hCbHandle, pTxn); } /* In the normal case (no restart), enqueue completed transaction in TxnDone queue */ else { TI_STATUS eStatus; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pTxn); if (eStatus != TI_OK) { TRACE3(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_TxnDoneCb(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pTxn, pTxn->uHwAddr, pTxn->aLen[0]); } context_LeaveCriticalSection (pTxnQ->hContext); } /* Indicate that no transaction is currently processed in the bus-driver */ pTxnQ->pCurrTxn = NULL; /* Send queued transactions as possible (TRUE indicates we are in external context) */ txnQ_RunScheduler (pTxnQ, NULL); }
/** * \fn txnQ_Restart * \brief Restart caller's queues * * Called upon functional driver stop command or upon recovery. * If no transaction in progress for the calling function, clear its queues (call the CBs). * If a transaction from this function is in progress, just set state to RESTART and when * called back upon TxnDone clear the queues. * Perform in critical section to prevent preemption from TxnDone. * Note that the Restart applies only to the calling function's queues. * * \note * \param hTxnQ - The module's object * \param uFuncId - The calling functional driver * \return COMPLETE if queues were restarted, PENDING if waiting for TxnDone to restart queues * \sa txnQ_ClearQueues */ ETxnStatus txnQ_Restart (handle_t hTxnQ, const McpU32 uFuncId) { TTxnQObj *pTxnQ = (TTxnQObj*) hTxnQ; #ifdef TRAN_DBG if (pTxnQ->aFuncInfo[uFuncId].eState != FUNC_STATE_RUNNING) { MCPF_REPORT_ERROR(pTxnQ->hMcpf, QUEUE_MODULE_LOG, ("%s: Called while func %d state is %d!\n", __FUNCTION__, uFuncId, pTxnQ->aFuncInfo[uFuncId].eState)); } #endif MCPF_ENTER_CRIT_SEC (pTxnQ->hMcpf); /* If a Txn from the calling function is in progress, set state to RESTART return PENDING */ if (pTxnQ->pCurrTxn) { if (TXN_PARAM_GET_FUNC_ID(pTxnQ->pCurrTxn) == uFuncId) { pTxnQ->aFuncInfo[uFuncId].eState = FUNC_STATE_RESTART; MCPF_EXIT_CRIT_SEC (pTxnQ->hMcpf); /* Return PENDING to indicate that the restart will be completed later (in TxnDone) */ return TXN_STATUS_PENDING; } } /* Clear the calling function's queues (call function CB with status=RECOVERY) */ txnQ_ClearQueues (pTxnQ, uFuncId, MCP_FALSE); MCPF_EXIT_CRIT_SEC (pTxnQ->hMcpf); /* Return COMPLETE to indicate that the restart was completed */ return TXN_STATUS_COMPLETE; }
ETxnStatus txnQ_Transact (TI_HANDLE hTxnQ, TTxnStruct *pTxn) { TTxnQObj *pTxnQ = (TTxnQObj*)hTxnQ; TI_UINT32 uFuncId = TXN_PARAM_GET_FUNC_ID(pTxn); ETxnStatus rc; if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { pTxnQ->aFuncInfo[uFuncId].pSingleStep = pTxn; } else { TI_STATUS eStatus; TI_HANDLE hQueue = pTxnQ->aTxnQueues[uFuncId][TXN_PARAM_GET_PRIORITY(pTxn)]; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (hQueue, (TI_HANDLE)pTxn); context_LeaveCriticalSection (pTxnQ->hContext); if (eStatus != TI_OK) { return TXN_STATUS_ERROR; } } /* Send queued transactions as possible */ rc = txnQ_RunScheduler (pTxnQ, pTxn); return rc; }
/** * \fn busDrv_SendTxnParts * \brief Send prepared transaction parts * * Called first by busDrv_Transact(), and also from TxnDone CB after Async completion. * Sends the prepared transaction parts in a loop. * If a transaction part is Async, the loop continues later in the TxnDone ISR context. * When all parts are done, the upper layer TxnDone CB is called. * * \note * \param pBusDrv - The module's object * \return void * \sa busDrv_Transact, busDrv_PrepareTxnParts */ static void busDrv_SendTxnParts (TBusDrvObj *pBusDrv) { ETxnStatus eStatus; TTxnPart *pTxnPart; TTxnStruct *pTxn = pBusDrv->pCurrTxn; /* While there are transaction parts to send */ while (pBusDrv->uCurrTxnPartsCount < pBusDrv->uCurrTxnPartsNum) { pTxnPart = &(pBusDrv->aTxnParts[pBusDrv->uCurrTxnPartsCount]); pBusDrv->uCurrTxnPartsCount++; /* Assume pending to be ready in case we are preempted by the TxnDon CB !! */ pBusDrv->eCurrTxnStatus = TXN_STATUS_PENDING; /* If single step, send ELP byte */ if (TXN_PARAM_GET_SINGLE_STEP(pTxn)) { /* Overwrite the function id with function 0 - for ELP register !!!! */ eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL, pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->bMore); /* If first write failed try once again (may happen once upon chip wakeup) */ if (eStatus == TXN_STATUS_ERROR) { /* Overwrite the function id with function 0 - for ELP register !!!! */ eStatus = sdioAdapt_TransactBytes (TXN_FUNC_ID_CTRL, pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->bMore); TRACE0(pBusDrv->hReport, REPORT_SEVERITY_WARNING, "busDrv_SendTxnParts: SDIO Single-Step transaction failed once so try again"); } } else { eStatus = sdioAdapt_Transact (TXN_PARAM_GET_FUNC_ID(pTxn), pTxnPart->uHwAddr, pTxnPart->pHostAddr, pTxnPart->uLength, TXN_PARAM_GET_DIRECTION(pTxn), pTxnPart->bBlkMode, ((TXN_PARAM_GET_FIXED_ADDR(pTxn) == 1) ? 0 : 1), pTxnPart->bMore); } 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); /* If pending TxnDone (Async), continue this loop in the next TxnDone interrupt */ if (eStatus == TXN_STATUS_PENDING) { return; } /* Update current transaction status to deduce if it is all finished in the original context (Sync) or not. */ pBusDrv->eCurrTxnStatus = eStatus; pBusDrv->uCurrTxnPartsCountSync++; /* If error, set error in Txn struct, call TxnDone CB if not fully sync, and exit */ if (eStatus == TXN_STATUS_ERROR) { TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_ERROR); if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount) { pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn); } return; } } /* If we got here we sent all buffers and we don't pend transaction end */ TRACE3(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_SendTxnParts: Txn finished successfully, Status = %d, PartsCount = %d, SyncCount = %d\n", pBusDrv->eCurrTxnStatus, pBusDrv->uCurrTxnPartsCount, pBusDrv->uCurrTxnPartsCountSync); /* For read transaction, copy the data from the DMA-able buffer to the host buffer(s) */ if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_READ) { TI_UINT32 uBufNum; TI_UINT32 uBufLen; TI_UINT8 *pDmaBuf = pBusDrv->pRxDmaBuf; /* After the read transaction the data is in the Rx DMA buffer */ for (uBufNum = 0; uBufNum < MAX_XFER_BUFS; uBufNum++) { uBufLen = pTxn->aLen[uBufNum]; /* If no more buffers, exit the loop */ if (uBufLen == 0) { break; } os_memoryCopy (pBusDrv->hOs, pTxn->aBuf[uBufNum], pDmaBuf, uBufLen); pDmaBuf += uBufLen; } } /* If not fully sync, call TxnDone CB */ if (pBusDrv->uCurrTxnPartsCountSync != pBusDrv->uCurrTxnPartsCount) { pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pTxn); } }
/** * \fn txnQ_Scheduler * \brief Send queued transactions * * Issue transactions as long as they are available and the bus is not occupied. * Call CBs of completed transactions, except completion of pInputTxn (covered by the return value). * Note that this function is called from either internal or external (TxnDone) context. * However, the txnQ_RunScheduler which calls it, prevents scheduler reentry. * * \note * \param pTxnQ - The module's object * \param pInputTxn - The transaction inserted in the current context (NULL if none) * \return COMPLETE if pInputTxn completed in this context, PENDING if not, ERROR if failed * \sa txnQ_RunScheduler */ static ETxnStatus txnQ_Scheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn) { ETxnStatus eInputTxnStatus; /* Use as return value the status of the input transaction (PENDING unless sent and completed here) */ eInputTxnStatus = TXN_STATUS_PENDING; /* if a previous transaction is in progress, return PENDING */ if (pTxnQ->pCurrTxn) { TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): pCurrTxn isn't null (0x%x) so exit\n", pTxnQ->pCurrTxn); return TXN_STATUS_PENDING; } /* Loop while transactions are available and can be sent to bus driver */ while (1) { TTxnStruct *pSelectedTxn; ETxnStatus eStatus; /* Get next enabled transaction by priority. If none, exit loop. */ context_EnterCriticalSection (pTxnQ->hContext); pSelectedTxn = txnQ_SelectTxn (pTxnQ); context_LeaveCriticalSection (pTxnQ->hContext); if (pSelectedTxn == NULL) { break; } /* Save transaction in case it will be async (to indicate that the bus driver is busy) */ pTxnQ->pCurrTxn = pSelectedTxn; /* Send selected transaction to bus driver */ eStatus = busDrv_Transact (pTxnQ->hBusDrv, pSelectedTxn); /* If we've just sent the input transaction, use the status as the return value */ if (pSelectedTxn == pInputTxn) { eInputTxnStatus = eStatus; } TRACE3(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Txn 0x%x sent, status = %d, eInputTxnStatus = %d\n", pSelectedTxn, eStatus, eInputTxnStatus); /* If transaction completed */ if (eStatus != TXN_STATUS_PENDING) { pTxnQ->pCurrTxn = NULL; /* If it's not the input transaction, enqueue it in TxnDone queue */ if (pSelectedTxn != pInputTxn) { TI_STATUS eStatus; context_EnterCriticalSection (pTxnQ->hContext); eStatus = que_Enqueue (pTxnQ->hTxnDoneQueue, (TI_HANDLE)pSelectedTxn); if (eStatus != TI_OK) { TRACE3(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_Scheduler(): Enqueue failed, pTxn=0x%x, HwAddr=0x%x, Len0=%d\n", pSelectedTxn, pSelectedTxn->uHwAddr, pSelectedTxn->aLen[0]); } context_LeaveCriticalSection (pTxnQ->hContext); } } /* If pending Exit loop! */ else { break; } } /* Dequeue completed transactions and call their functional driver CB */ /* Note that it's the functional driver CB and not the specific CB in the Txn! */ while (1) { TTxnStruct *pCompletedTxn; TI_UINT32 uFuncId; TTxnQueueDoneCb fTxnQueueDoneCb; TI_HANDLE hCbHandle; context_EnterCriticalSection (pTxnQ->hContext); pCompletedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->hTxnDoneQueue); context_LeaveCriticalSection (pTxnQ->hContext); if (pCompletedTxn == NULL) { /* Return the status of the input transaction (PENDING unless sent and completed here) */ return eInputTxnStatus; } TRACE1(pTxnQ->hReport, REPORT_SEVERITY_INFORMATION, "txnQ_Scheduler(): Calling TxnDone for Txn 0x%x\n", pCompletedTxn); uFuncId = TXN_PARAM_GET_FUNC_ID(pCompletedTxn); fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb; hCbHandle = pTxnQ->aFuncInfo[uFuncId].hCbHandle; fTxnQueueDoneCb (hCbHandle, pCompletedTxn); } }
/** * \fn txnQ_RunScheduler * \brief Send queued transactions * * Issue transactions as long as they are available and the bus is not occupied. * Call CBs of completed transactions, except conpletion of pCurrTxn (covered by the return value). * Note that this function can't be preempted, since it is always called in critical section * See txnQ_Transact(), txnQ_SendCtrlByte(), txnQ_Run() and txnQ_TxnDoneCb(). * * \note * \param pTxnQ - The module's object * \param pCurrTxn - The transaction inserted in the current context (NULL if none) * \param bExternalContext - TRUE if called in external context (TxnDone) * \return COMPLETE if pCurrTxn completed in this context, PENDING if not, ERROR if failed * \sa */ static ETxnStatus txnQ_RunScheduler (TTxnQObj *pTxnQ, TTxnStruct *pInputTxn, McpBool bExternalContext) { /* Use as return value the status of the input transaction (PENDING unless sent and completed here) */ ETxnStatus eInputTxnStatus = TXN_STATUS_PENDING; McpBool loopCond = MCP_TRUE; /* if a previous transaction is in progress, return PENDING */ if (pTxnQ->pCurrTxn) { return TXN_STATUS_PENDING; } /* Loop while transactions are available and can be sent to bus driver */ while (loopCond) { TTxnStruct *pSelectedTxn; ETxnStatus eStatus; #ifdef TRAN_DBG #define TXN_MAX_LOOP_ITERATES 100 int loopIterates = 0; if (loopIterates++ >= TXN_MAX_LOOP_ITERATES) { MCPF_REPORT_WARNING (pTxnQ->hMcpf, QUEUE_MODULE_LOG, ("txnQ_RunScheduler loop reached max iterates=%d\n", loopIterates)); } #endif /* Get next enabled transaction by priority. If none, exit loop. */ pSelectedTxn = txnQ_SelectTxn (pTxnQ); if (pSelectedTxn == NULL) { break; } /* Send selected transaction to bus driver */ eStatus = busDrv_Transact (pTxnQ->hBusDrv, pSelectedTxn); /* If we've just sent the input transaction, use the status as the return value */ if (pSelectedTxn == pInputTxn) { eInputTxnStatus = eStatus; } /* If transaction completed */ if (eStatus == TXN_STATUS_COMPLETE) { /* If it's not the input transaction, enqueue it in TxnDone queue */ if (pSelectedTxn != pInputTxn) { que_Enqueue (pTxnQ->hTxnDoneQueue, (handle_t)pSelectedTxn); } } /* If pending or error */ else { /* If transaction pending, save it to indicate that the bus driver is busy */ if (eStatus == TXN_STATUS_PENDING) { pTxnQ->pCurrTxn = pSelectedTxn; } /* Exit loop! */ break; } } /* Dequeue completed transactions and call their functional driver CB */ /* Note that it's the functional driver CB and not the specific CB in the Txn! */ while (loopCond) { TTxnStruct *pCompletedTxn; McpU32 uFuncId; TTxnQueueDoneCb fTxnQueueDoneCb; handle_t hCbHandle; pCompletedTxn = (TTxnStruct *) que_Dequeue (pTxnQ->hTxnDoneQueue); if (pCompletedTxn == NULL) { /* Return the status of the input transaction (PENDING unless sent and completed here) */ return eInputTxnStatus; } uFuncId = TXN_PARAM_GET_FUNC_ID(pCompletedTxn); fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb; hCbHandle = pTxnQ->aFuncInfo[uFuncId].hCbHandle; fTxnQueueDoneCb (hCbHandle, pCompletedTxn, bExternalContext); } return TXN_STATUS_PENDING; }