Esempio n. 1
0
/**
 * \fn     busDrv_Transact
 * \brief  Process transaction
 *
 * Called by the TxnQ module to initiate a new transaction.
 * Call either write or read functions according to Txn direction field.
 *
 * \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;
	WSPI_CB_T cb;
	TI_UINT8 * tempReadBuff;
	TI_UINT8 * tempWriteBuff;
	pBusDrv->pCurrTxn       = pTxn;
	pBusDrv->eCurrTxnStatus = TXN_STATUS_COMPLETE;  /* The Txn is Sync as long as it continues in this context */
	cb.CBFunc = asyncEnded_CB;  /* The BusTxn callback called upon Async transaction end. */
	cb.CBArg  = hBusDrv;   /* The handle for the BusTxnCB. */

	/* If write command */
	if (TXN_PARAM_GET_DIRECTION(pTxn) == TXN_DIRECTION_WRITE) {

		//WLAN_REPORT_INIT(pBusDrv->hReport, TNETW_DRV_MODULE_LOG,
		//    ("busDrv_Transact:  Write to pTxn->uHwAddr %x\n", pTxn->uHwAddr ));


		/*WLAN_REPORT_ERROR(pBusDrv->hReport, BUS_DRV_MODULE_LOG,
		   ("busDrv_Transact: Buff= %x, Len=%d\n", pTxn->aBuf[0], pTxn->aLen[0]));*/
		/*1.write memory*/
		/* Decrease the data pointer to the beginning of the WSPI padding */
		tempWriteBuff = pTxn->aBuf[0];
		tempWriteBuff -= WSPI_PAD_LEN_WRITE;

		/* Write the data to the WSPI in Aync mode (not completed in the current context). */
		pBusDrv->eCurrTxnStatus = WSPI_WriteAsync(pBusDrv->hWspi, pTxn->uHwAddr,tempWriteBuff,pTxn->aLen[0], &cb, TI_TRUE, TI_TRUE,TXN_PARAM_GET_FIXED_ADDR(pTxn));

	}

	/* If read command */
	else {
		//WLAN_REPORT_INIT(pBusDrv->hReport, TNETW_DRV_MODULE_LOG,
		//    ("busDrv_Transact:  Read from pTxn->uHwAddr %x pTxn %x \n", pTxn->uHwAddr,pTxn));

		/*1. Read mem */
		/* Decrease the tempReadBuff pointer to the beginning of the WSPI padding */
		tempReadBuff = pTxn->aBuf[0];
		tempReadBuff -= WSPI_PAD_LEN_READ;
		/* Read the required data from the WSPI in Aync mode (not completed in the current context). */
		pBusDrv->eCurrTxnStatus  = WSPI_ReadAsync(pBusDrv->hWspi, pTxn->uHwAddr,tempReadBuff,pTxn->aLen[0], &cb, TI_TRUE, TI_TRUE,TXN_PARAM_GET_FIXED_ADDR(pTxn));


	}

	/* return transaction status - COMPLETE, PENDING or ERROR */
	return (pBusDrv->eCurrTxnStatus == WSPI_TXN_COMPLETE ? TXN_STATUS_COMPLETE :
	        (pBusDrv->eCurrTxnStatus == WSPI_TXN_PENDING ? TXN_STATUS_PENDING : TXN_STATUS_ERROR));


}
/** 
 * \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;
}
/** 
 * \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);
    }
}
Esempio n. 4
0
/** 
 * \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) 
            {
                if ((TXN_PARAM_GET_FIXED_ADDR(pSelectedTxn) != TXN_FIXED_ADDR) ||
                    (TXN_PARAM_GET_DIRECTION(pSelectedTxn)  != TXN_DIRECTION_WRITE))
                {
                    TRACE2(pTxnQ->hReport, REPORT_SEVERITY_ERROR, "txnQ_SelectTxn: Mixed transaction during aggregation, HwAddr=0x%x, TxnParams=0x%x\n", pSelectedTxn->uHwAddr, pSelectedTxn->uTxnParams);
                }
                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;
}