/** 
 * \fn     busDrv_Transact
 * \brief  Process transaction 
 * 
 * Called by the TxnQ module to initiate a new transaction.
 * Prepare the transaction parts (lower layer single transactions),
 *      and send them one by one to the lower layer.
 * 
 * \note   It's assumed that this function is called only when idle (i.e. previous Txn is done).
 * \param  hBusDrv - The module's object
 * \param  pTxn    - The transaction object 
 * \return COMPLETE if Txn completed in this context, PENDING if not, ERROR if failed
 * \sa     busDrv_PrepareTxnParts, busDrv_SendTxnParts
 */ 
ETxnStatus busDrv_Transact (TI_HANDLE hBusDrv, TTxnStruct *pTxn)
{
    TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
    TI_BOOL     bWithinAggregation;
    CL_TRACE_START_L4();

    pBusDrv->pCurrTxn               = pTxn;
    pBusDrv->uCurrTxnPartsCount     = 0;
    pBusDrv->uCurrTxnPartsCountSync = 0;

    /* Set status OK in Txn struct (changed later to error if transaction fails) */
    TXN_PARAM_SET_STATUS(pTxn, TXN_PARAM_STATUS_OK);

    /* Prepare the transaction parts in a table. */
    bWithinAggregation = busDrv_PrepareTxnParts (pBusDrv, pTxn);

    /* If in the middle of Tx aggregation, return Complete (current Txn was coppied to buffer but not sent) */
    if (bWithinAggregation)
    {
        TRACE1(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_Transact: In aggregation so exit, uTxnLength=%d\n", pBusDrv->uTxnLength);
        CL_TRACE_END_L4("tiwlan_drv.ko", "INHERIT", "TXN", ".Transact");
        return TXN_STATUS_COMPLETE;
    }

    /* Send the prepared transaction parts. */
    busDrv_SendTxnParts (pBusDrv);

    TRACE1(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_Transact: Status = %d\n", pBusDrv->eCurrTxnStatus);

    CL_TRACE_END_L4("tiwlan_drv.ko", "INHERIT", "TXN", ".Transact");

    /* return transaction status - COMPLETE, PENDING or ERROR */
    /* The status is updated in busDrv_SendTxnParts(). It is Async (pending) if not completed in this context */
    return pBusDrv->eCurrTxnStatus;
}
Example #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);
}
Example #3
0
/****************************************************************************
 *                      ConnectDone_CB()
 ****************************************************************************
 * DESCRIPTION:
 *      Called back by the WSPI driver from Async transaction end interrupt (ISR context).
 *      Calls the upper layers callback.
 *
 * INPUTS:  status -
 *
 * OUTPUT:  None
 *
 * RETURNS: None
 ****************************************************************************/
static void ConnectDone_CB(TI_HANDLE hBusDrv, int status)
{
	TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
	/* If the last transaction failed, call failure CB and exit. */
	if (status != 0) {

		TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR);
	}

	/* Call the upper layer CB */

	pBusDrv->fTxnConnectDoneCb(pBusDrv->hCbHandle,pBusDrv->pCurrTxn);
}
/** 
 * \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_ClearQueues
 * \brief  Clear the function queues
 * 
 * Clear the specified function queues and call its CB for each Txn with status=RECOVERY.
 * 
 * \note   Called in critical section.
 * \param  pTxnQ            - The module's object
 * \param  uFuncId          - The calling functional driver
 * \param  bExternalContext - TRUE if called in external context (TxnDone)
 * \return void
 * \sa     
 */ 
static void txnQ_ClearQueues (TTxnQObj *pTxnQ, McpU32 uFuncId, McpBool bExternalContext)
{
    TTxnStruct      *pTxn;
    McpU32        uPrio;
    TTxnQueueDoneCb  fTxnQueueDoneCb = pTxnQ->aFuncInfo[uFuncId].fTxnQueueDoneCb; /* function TxnDone CB */
    handle_t        hCbHandle       = pTxnQ->aFuncInfo[uFuncId].hCbHandle;
	McpBool loopCond = MCP_TRUE;

    /* If single step waiting in this function, call function CB with recovery indication */
    pTxn = pTxnQ->aFuncInfo[uFuncId].pSingleStep;
    if (pTxn != NULL)
    {
        TXN_PARAM_SET_STATUS(pTxn, TXN_STATUS_RECOVERY);
        fTxnQueueDoneCb (hCbHandle, pTxn, bExternalContext);
    }

    /* For all function priorities */
    for (uPrio = 0; uPrio < pTxnQ->aFuncInfo[uFuncId].uNumPrios; uPrio++)
    {
        while (loopCond) 
        {
            /* Dequeue Txn from current priority queue */
            pTxn = (TTxnStruct *) que_Dequeue (pTxnQ->aTxnQueues[uFuncId][uPrio]);

            /* If NULL Txn (queue empty), exit while loop */
            if (pTxn == NULL)
            {
                break;
            }

            /* Call function CB with recovery indication in the Txn */
            TXN_PARAM_SET_STATUS(pTxn, TXN_STATUS_RECOVERY);
            fTxnQueueDoneCb (hCbHandle, pTxn, bExternalContext);
        }
    }
}
Example #6
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);

#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); 
}
Example #7
0
/****************************************************************************
 *                      ConnectDone_CB()
 ****************************************************************************
 * DESCRIPTION:
 *      Called back by the WSPI driver from Async transaction end interrupt (ISR context).
 *      Calls the upper layers callback.
 *
 * INPUTS:  status -
 *
 * OUTPUT:  None
 *
 * RETURNS: None
 ****************************************************************************/
static void ConnectDone_CB(TI_HANDLE hBusDrv, int status)
{
	TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
	/* If the last transaction failed, call failure CB and exit. */
	if (status != 0)
	{
		TRACE2(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "ConnectDone_CB : Status = %d, fTxnConnectDoneCb = 0x%x\n", status,pBusDrv->fTxnConnectDoneCb);

		TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR);
	}
	else
	{
		TRACE1 (pBusDrv->hReport, REPORT_SEVERITY_INIT, "ConnectDone_CB: Successful Connect Async cb done \n");
	}

	/* Call the upper layer CB */

	pBusDrv->fTxnConnectDoneCb(pBusDrv->hCbHandle,pBusDrv->pCurrTxn);
}
/** 
 * \fn     busDrv_TxnDoneCb
 * \brief  Continue async transaction processing (CB)
 * 
 * Called back by the lower (BSP) bus-driver upon Async transaction completion (TxnDone ISR).
 * Call busDrv_SendTxnParts to continue sending the remained transaction parts.
 * 
 * \note   
 * \param  hBusDrv - The module's object
 * \param  status  - The last transaction result - 0 = OK, else Error
 * \return void
 * \sa     busDrv_SendTxnParts
 */ 
static void busDrv_TxnDoneCb (TI_HANDLE hBusDrv, int iStatus)
{
    TBusDrvObj *pBusDrv = (TBusDrvObj*)hBusDrv;
    CL_TRACE_START_L1();

    /* If last transaction part failed, set error in Txn struct, call TxnDone CB and exit. */
    if (iStatus != 0)
    {
        TRACE1(pBusDrv->hReport, REPORT_SEVERITY_ERROR, "busDrv_TxnDoneCb: Status = 0x%x\n", iStatus);

        TXN_PARAM_SET_STATUS(pBusDrv->pCurrTxn, TXN_PARAM_STATUS_ERROR);
        pBusDrv->fTxnDoneCb (pBusDrv->hCbHandle, pBusDrv->pCurrTxn);
        CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", "");
        return;
    }

    TRACE0(pBusDrv->hReport, REPORT_SEVERITY_INFORMATION, "busDrv_TxnDoneCb()\n");

    /* Continue sending the remained transaction parts. */
    busDrv_SendTxnParts (pBusDrv);

    CL_TRACE_END_L1("tiwlan_drv.ko", "TXN_DONE", "BusDrvCB", "");
}
/** 
 * \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);
    }
}