예제 #1
0
파일: TxnQueue.c 프로젝트: aleho/ti_wilink
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;
}
예제 #2
0
/**
 * \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);
}
예제 #3
0
파일: TxnQueue.c 프로젝트: aleho/ti_wilink
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;
}
예제 #4
0
/** 
 * \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;
}
예제 #5
0
/** 
 * \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);
    }
}
예제 #6
0
파일: TxnQueue.c 프로젝트: aleho/ti_wilink
/** 
 * \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); 
}
예제 #7
0
/** 
 * \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;
}
예제 #8
0
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);
    }
}
예제 #10
0
파일: TxnQueue.c 프로젝트: aleho/ti_wilink
/** 
 * \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);
    }
}
예제 #11
0
/** 
 * \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;
}