/* * \brief Send the Command to the Mailbox * * \param hCmdMbox - Handle to CmdMbox * \param cmdType - * \param pParamsBuf - The buffer that will be written to the mailbox * \param uWriteLen - Length of data to write to the mailbox * \param uReadLen - Length of data to read from the mailbox (when the result is received) * \return TI_PENDING * * \par Description * Copy the buffer given to a local struct, update the write & read lengths * and send to the FW's mailbox. * * ------------------------------------------------------ * | CmdMbox Header | Cmd Header | Command parameters | * ------------------------------------------------------ * | ID | Status | Type | Length | Command parameters | * ------------------------------------------------------ * 16bit 16bit 16bit 16bit * * \sa cmdMbox_CommandComplete */ TI_STATUS cmdMbox_SendCommand (TI_HANDLE hCmdMbox, Command_e cmdType, TI_UINT8* pParamsBuf, TI_UINT32 uWriteLen, TI_UINT32 uReadLen) { TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[0].tTxnStruct; TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[0].tTxnStruct; Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[0].tCmdMbox; if (pCmdMbox->bCmdInProgress) { TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_SendCommand(): Trying to send Cmd while other Cmd is still in progres!\n"); return TI_NOK; } /* Add the CMDMBOX_HEADER_LEN to the read length, used when reading the result later on */ pCmdMbox->uReadLen = uReadLen + CMDMBOX_HEADER_LEN; /* Prepare the Cmd Hw template */ pCmd->cmdID = cmdType; pCmd->cmdStatus = CMD_STATUS_SUCCESS; os_memoryCopy (pCmdMbox->hOs, (void *)pCmd->parameters, (void *)pParamsBuf, uWriteLen); /* Add the CMDMBOX_HEADER_LEN to the write length */ pCmdMbox->uWriteLen = uWriteLen + CMDMBOX_HEADER_LEN; /* Must make sure that the length is multiple of 32 bit */ if (pCmdMbox->uWriteLen & 0x3) { TRACE1(pCmdMbox->hReport, REPORT_SEVERITY_WARNING, "cmdMbox_SendCommand(): Command length isn't 32bit aligned! CmdId=%d\n", pCmd->cmdID); pCmdMbox->uWriteLen = (pCmdMbox->uWriteLen + 4) & 0xFFFFFFFC; } /* no other command can start the send process till bCmdInProgress will return to TI_FALSE*/ pCmdMbox->bCmdInProgress = TI_TRUE; /* Build the command TxnStruct */ TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uWriteLen, NULL, NULL) /* Send the command */ twIf_Transact(pCmdMbox->hTwIf, pCmdTxn); /* Build the trig TxnStruct */ pCmdMbox->aRegTxn[0].uRegister = INTR_TRIG_CMD; TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) BUILD_TTxnStruct(pRegTxn, ACX_REG_INTERRUPT_TRIG, &(pCmdMbox->aRegTxn[0].uRegister), REGISTER_SIZE, NULL, NULL) /* start the CmdMbox timer */ tmr_StartTimer (pCmdMbox->hCmdMboxTimer, cmdMbox_TimeOut, hCmdMbox, CMDMBOX_WAIT_TIMEOUT, TI_FALSE); /* Send the FW trigger */ twIf_Transact(pCmdMbox->hTwIf, pRegTxn); return TXN_STATUS_PENDING; }
/* * \brief Read interrupt info from FW * * \param hFwEvent - FwEvent Driver handle * \return void * * \par Description * * Indicate the TwIf that HW is available and initiate transactions for reading * the Interrupt status and the FW status. * * \sa */ static ETxnStatus fwEvent_SmReadIntrInfo (TfwEvent *pFwEvent) { ETxnStatus eStatus; CL_TRACE_START_L4(); #ifdef HOST_INTR_MODE_EDGE /* Acknowledge the host interrupt for EDGE mode (must be before HINT_STT_CLR register clear on read) */ os_InterruptServiced (pFwEvent->hOs); #endif /* Indicate that the chip is awake (since it interrupted us) */ twIf_HwAvailable(pFwEvent->hTwIf); /* * Read FW-Status structure from HW ==> Special mapping, see note!! * * Note: This structure actually includes two separate areas in the FW: * 1) Interrupt-Status register - a 32 bit register (clear on read). * 2) FW-Status structure - 64 bytes memory area * The two areas are read in a single transaction thanks to a special memory * partition that maps them as contiguous memory. */ TXN_FW_EVENT_SET_FW_STAT_ADDR(pFwEvent) #if defined(READ_FW_STATUS_FROM_REG_AREA) //|| defined(TNETW1273_FPGA) /* Read FW status from registers area */ eStatus = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct)); #else eStatus = twIf_TransactReadFWStatus (pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct)); #endif CL_TRACE_END_L4("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); /* Return the status of the FwStatus read (complete, pending or error) */ return eStatus; }
/* * \brief Read the command's result * * \param hCmdMbox - Handle to CmdMbox * \return void * * \par Description * This function is called from FwEvent module uppon receiving command complete interrupt. * It issues a read transaction from the mailbox with a CB. * * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete */ ETxnStatus cmdMbox_CommandComplete (TI_HANDLE hCmdMbox) { TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[1].tTxnStruct; Command_t *pCmd = (Command_t*)&pCmdMbox->aCmdTxn[1].tCmdMbox; ETxnStatus rc; /* stop the CmdMbox timer */ tmr_StopTimer(pCmdMbox->hCmdMboxTimer); /* Build the command TxnStruct */ TXN_PARAM_SET(pCmdTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) /* Applying a CB in case of an async read */ BUILD_TTxnStruct(pCmdTxn, pCmdMbox->uFwAddr, pCmd, pCmdMbox->uReadLen,(TTxnDoneCb)cmdMbox_TransferComplete, hCmdMbox) /* Send the command */ rc = twIf_Transact(pCmdMbox->hTwIf, pCmdTxn); /* In case of a sync read, call the CB directly */ if (rc == TXN_STATUS_COMPLETE) { cmdMbox_TransferComplete(hCmdMbox); } return TXN_STATUS_COMPLETE; }
/* * \brief Read Address to FW * * \param hFwDebug - Handle to FW Debug * \param Address - Absolute HW address * \param Length - Length in byte to write * \param Buffer - Buffer to copy to FW * \param fCb - CB function * \param hCb - CB Handle * \return none * * \par Description * Read from HW, must receive length in byte max size 256 bytes * address must be absolute HW address. * * \sa */ TI_STATUS fwDbg_ReadAddr (TI_HANDLE hFwDebug, TI_UINT32 Address, TI_UINT32 Length, TI_UINT8* Buffer, TFwDubCallback fCb, TI_HANDLE hCb) { TI_STATUS rc; TTxnStruct *pTxn; TFwDebug *pFwDebug = (TFwDebug*)hFwDebug; pTxn = &pFwDebug->tTxn; /* check if length is large than default threshold */ if (Length > DMA_SIZE_BUF) { TRACE1(pFwDebug->hReport, REPORT_SEVERITY_ERROR, "fwDbg_ReadAddr : Buffer Length too large -- %d",Length); return TXN_STATUS_ERROR; } pFwDebug->fCb = fCb; pFwDebug->hCb = hCb; pFwDebug->pReadBuf = Buffer; /* Build the command TxnStruct */ TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) /* Applying a CB in case of an async read */ BUILD_TTxnStruct(pTxn, Address, pFwDebug->pDMABuf, Length,(TTxnDoneCb)fwDbg_ReadAddrCb, pFwDebug) rc = twIf_Transact(pFwDebug->hTwif,pTxn); if (rc == TXN_STATUS_COMPLETE) { /* copy from DMA buufer to given buffer */ os_memoryCopy(pFwDebug->hOs,pFwDebug->pReadBuf,pFwDebug->pDMABuf,Length); } return rc; }
/* * \brief Read mailbox address * * \param hEventMbox - Handle to EventMbox * \param fCb - CB function to return in Async mode * \param hCb - CB Habdle * \return TXN_STATUS_COMPLETE, TXN_STATUS_PENDING, TXN_STATUS_ERROR * * \par Description * This function is called for initialize the Event MBOX addresses. * It issues a read transaction from the Twif with a CB. * * \sa */ TI_STATUS eventMbox_InitMboxAddr(TI_HANDLE hEventMbox, fnotify_t fCb, TI_HANDLE hCb) { TTxnStruct *pTxn; TEventMbox* pEventMbox; ETxnStatus rc; pEventMbox = (TEventMbox*)hEventMbox; pTxn = &pEventMbox->iTxnGenRegSize.tTxnReg; /* Store the Callabck address of the modules that called us in case of Asynchronuous transaction that will complete later */ pEventMbox->fCb = fCb; pEventMbox->hCb = hCb; /* Build the command TxnStruct */ TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) /* Applying a CB in case of an async read */ BUILD_TTxnStruct(pTxn, REG_EVENT_MAILBOX_PTR, &pEventMbox->iTxnGenRegSize.iRegBuffer, REGISTER_SIZE, eventMbox_ReadAddrCb, hEventMbox) rc = twIf_Transact(pEventMbox->hTwif,pTxn); if (rc == TXN_STATUS_COMPLETE) { pEventMbox->EventMboxAddr[0] = pEventMbox->iTxnGenRegSize.iRegBuffer; pEventMbox->EventMboxAddr[1] = pEventMbox->EventMboxAddr[0] + sizeof(EventMailBox_t); TRACE3(pEventMbox->hReport, REPORT_SEVERITY_INIT , "eventMbox_ConfigHw: event A Address=0x%x, event B Address=0x%x, sizeof=%d\n", pEventMbox->EventMboxAddr[0], pEventMbox->EventMboxAddr[1], sizeof(EventMailBox_t)); } return rc; }
/**************************************************************************** * txResult_HandleNewResults() **************************************************************************** * DESCRIPTION: * ============ * We now have the Tx Result table info from the FW so do as follows: * 1. Find the number of new results (FW counter minus host counter), and if 0 exit. * 2. Call the upper layers callback per Tx result. * 3. Update Host-Counter to be equal to the FW-Counter, and write it to the FW. ***************************************************************************/ static void txResult_HandleNewResults (TTxResultObj *pTxResult) { TI_UINT32 uNumNewResults; /* The number of new Tx-Result entries to be processed. */ TI_UINT32 uFwResultsCounter; /* The FW current results counter (accumulated). */ TI_UINT32 uTableIndex; TI_UINT32 i; TxResultDescriptor_t *pCurrentResult; TTxnStruct *pTxn = &(pTxResult->tHostCounterWriteTxn.tTxnStruct); /* The uFwResultsCounter is the accumulated number of Tx-Results provided by the FW, and the * uHostResultsCounter is the accumulated number of Tx-Results processed by the host. * The delta is the number of new Tx-results in the queue, waiting for host processing. * Since the difference is always a small positive number, a simple subtraction is good * also for wrap around case. */ uFwResultsCounter = ENDIAN_HANDLE_LONG(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultControl.TxResultFwCounter); uNumNewResults = uFwResultsCounter - pTxResult->uHostResultsCounter; #ifdef TI_DBG /* Verify there are new entries (was already checked in txResult_TxCmpltIntrCb) */ if (uNumNewResults == 0) { TRACE2(pTxResult->hReport, REPORT_SEVERITY_WARNING, ": No New Results although indicated by FwStatus!! HostCount=%d, FwCount=%d\n", pTxResult->uHostResultsCounter, uFwResultsCounter); return; } #endif /* Update host results-counter in FW to be equal to the FW counter (all new results were processed). */ pTxResult->tHostCounterWriteTxn.uCounter = ENDIAN_HANDLE_LONG(uFwResultsCounter); pTxn->uHwAddr = pTxResult->uTxResultHostCounterAddr; twIf_Transact(pTxResult->hTwIf, pTxn); TRACE3(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": NumResults=%d, OriginalHostCount=%d, FwCount=%d\n", uNumNewResults, pTxResult->uHostResultsCounter, uFwResultsCounter); /* Loop over all new Tx-results and call Tx-complete callback with current entry pointer. */ /* NOTE: THIS SHOULD COME LAST because it may lead to driver-stop process!! */ for (i = 0; i < uNumNewResults; i++) { uTableIndex = pTxResult->uHostResultsCounter & TX_RESULT_QUEUE_DEPTH_MASK; pCurrentResult = &(pTxResult->tResultsInfoReadTxn.tTxResultInfo.TxResultQueue[uTableIndex]); pTxResult->uHostResultsCounter++; TRACE1(pTxResult->hReport, REPORT_SEVERITY_INFORMATION , ": call upper layer CB, Status = %d\n", pCurrentResult->status); pTxResult->fSendPacketCompleteCb (pTxResult->hSendPacketCompleteHndl, pCurrentResult); } }
/* * \brief configure the mailbox address. * * \param hCmdMbox - Handle to CmdMbox * \param fCb - Pointer to the CB * \param hCb - Cb's handle * \return TI_OK or TI_PENDING * * \par Description * Called from HwInit to read the command mailbox address. * * \sa */ TI_STATUS cmdMbox_ConfigHw (TI_HANDLE hCmdMbox, fnotify_t fCb, TI_HANDLE hCb) { TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; TTxnStruct *pRegTxn = (TTxnStruct*)&pCmdMbox->aRegTxn[1].tTxnStruct; TI_STATUS rc; pCmdMbox->fCb = fCb; pCmdMbox->hCb = hCb; /* Build the command TxnStruct */ TXN_PARAM_SET(pRegTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) BUILD_TTxnStruct(pRegTxn, REG_COMMAND_MAILBOX_PTR, &(pCmdMbox->aRegTxn[1].uRegister), REGISTER_SIZE,(TTxnDoneCb)cmdMbox_ConfigHwCb, hCmdMbox) /* Get the command mailbox address */ rc = twIf_Transact(pCmdMbox->hTwIf, pRegTxn); if (rc == TXN_STATUS_COMPLETE) { pCmdMbox->uFwAddr = pCmdMbox->aRegTxn[1].uRegister; } return rc; }
/* * \brief Handle the incoming event read the Mbox data * * \param hEventMbox - Handle to EventMbox * \param TFwStatus - FW status * \return none * * \par Description * This function is called from the FW Event upon receiving MBOX event. * \sa */ ETxnStatus eventMbox_Handle(TI_HANDLE hEventMbox,FwStatus_t* pFwStatus) { ETxnStatus rc; TTxnStruct *pTxn; TEventMbox *pEventMbox = (TEventMbox *)hEventMbox; pTxn = &pEventMbox->iTxnEventMbox.tEventMbox; TRACE1(pEventMbox->hReport, REPORT_SEVERITY_INFORMATION, "eventMbox_Handle : Reading from MBOX -- %d",pEventMbox->ActiveMbox); #ifdef TI_DBG /* Check if missmatch MBOX */ if (pEventMbox->ActiveMbox == 0) { if (pFwStatus->intrStatus & ACX_INTR_EVENT_B) { TRACE0(pEventMbox->hReport, REPORT_SEVERITY_ERROR, "eventMbox_Handle : incorrect MBOX SW MBOX -- A FW MBOX -- B"); } } else if (pEventMbox->ActiveMbox == 1) { if (pFwStatus->intrStatus & ACX_INTR_EVENT_A) { TRACE0(pEventMbox->hReport, REPORT_SEVERITY_ERROR, "eventMbox_Handle : incorrect MBOX SW MBOX -- B FW MBOX -- A"); } } #endif /* TI_DBG */ if (pEventMbox->CurrentState != EVENT_MBOX_STATE_IDLE) { TRACE0(pEventMbox->hReport, REPORT_SEVERITY_ERROR, "eventMbox_Handle : Receiving event not in Idle state"); } pEventMbox->CurrentState = EVENT_MBOX_STATE_READING; /* Build the command TxnStruct */ TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) /* Applying a CB in case of an async read */ BUILD_TTxnStruct(pTxn, pEventMbox->EventMboxAddr[pEventMbox->ActiveMbox], &pEventMbox->iTxnEventMbox.iEventMboxBuf, sizeof(EventMailBox_t),(TTxnDoneCb)eventMbox_ReadCompleteCB, pEventMbox) rc = twIf_Transact(pEventMbox->hTwif,pTxn); pEventMbox->ActiveMbox = 1 - pEventMbox->ActiveMbox; if (rc == TXN_STATUS_COMPLETE) { eventMbox_ReadCompleteCB(pEventMbox,pTxn); } return TXN_STATUS_COMPLETE; }
/**************************************************************************** * txResult_StateMachine() **************************************************************************** * DESCRIPTION: * * The main SM of the module. Called in IDLE eState by txResult_TxCmpltIntrCb() on * Data interrupt from the FW. * If no new results - exit (may happen since Data interrupt is common to all Tx&Rx events) * Read all Tx-Result cyclic table. * Go over the new Tx-results and call the upper layer callback function for each packet result. * At the end - write the new host counter to the FW. * * INPUTS: * * OUTPUT: * * RETURNS: None ****************************************************************************/ static void txResult_StateMachine (TI_HANDLE hTxResult) { TTxResultObj *pTxResult = (TTxResultObj *)hTxResult; ETxnStatus eTwifStatus = TXN_STATUS_COMPLETE; /* Last bus operation status: Complete (Sync) or Pending (Async). */ TTxnStruct *pTxn = &(pTxResult->tResultsInfoReadTxn.tTxnStruct); /* Loop while processing is completed in current context (sync), or until fully completed */ while (eTwifStatus == TXN_STATUS_COMPLETE) { TRACE2(pTxResult->hReport, REPORT_SEVERITY_INFORMATION, ": eState = %d, eTwifStatus = %d\n", pTxResult->eState, eTwifStatus); switch(pTxResult->eState) { case TX_RESULT_STATE_IDLE: /* Read Tx-Result queue and counters. */ pTxn->uHwAddr = pTxResult->uTxResultInfoAddr; eTwifStatus = twIf_Transact (pTxResult->hTwIf, pTxn); pTxResult->eState = TX_RESULT_STATE_READING; break; case TX_RESULT_STATE_READING: /* Process new Tx results, call upper layers to handle them and update host-index in the FW. */ txResult_HandleNewResults (pTxResult); pTxResult->eState = TX_RESULT_STATE_IDLE; return; /********* Exit after all processing is finished **********/ default: TRACE1(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": Unknown eState = %d\n", pTxResult->eState); return; } } if (eTwifStatus == TXN_STATUS_ERROR) { TRACE2(pTxResult->hReport, REPORT_SEVERITY_ERROR, ": returning ERROR in eState %d, eTwifStatus=%d !!!\n", pTxResult->eState, eTwifStatus); } }
/* * \brief Process the event * * \param hEventMbox - Handle to EventMbox * \param pTxnStruct - the Txn data * \return none * * \par Description * This function is called from the upon reading completion of the event MBOX * it will call all registered event according to the pending bits in event MBOX vector. * \sa */ static void eventMbox_ReadCompleteCB(TI_HANDLE hEventMbox, TTxnStruct *pTxnStruct) { TI_UINT32 EvID; TTxnStruct* pTxn; TEventMbox *pEventMbox = (TEventMbox *)hEventMbox; pTxn = &pEventMbox->iTxnGenRegSize.tTxnReg; pEventMbox->iTxnGenRegSize.iRegBuffer = INTR_TRIG_EVENT_ACK; for (EvID = 0; EvID < TWD_OWN_EVENT_ALL; EvID++) { if (pEventMbox->iTxnEventMbox.iEventMboxBuf.eventsVector & eventTable[EvID].bitMask) { if (eventTable[EvID].dataLen) { ((TEventMboxDataCb)pEventMbox->CbTable[EvID].fCb)(pEventMbox->CbTable[EvID].hCb,(TI_CHAR*)pEventMbox->CbTable[EvID].pDataOffset,eventTable[EvID].dataLen); } else { ((TEventMboxEvCb)pEventMbox->CbTable[EvID].fCb)(pEventMbox->CbTable[EvID].hCb); } } } /* Check if the state is changed in the context of the event callbacks */ if (pEventMbox->CurrentState == EVENT_MBOX_STATE_IDLE) { /* * When eventMbox_stop is called state is changed to IDLE * This is done in the context of the above events callbacks * Don't send the EVENT ACK transaction because the driver stop process includes power off */ TRACE0(pEventMbox->hReport, REPORT_SEVERITY_WARNING, "eventMbox_ReadCompleteCB : State is IDLE ! don't send the EVENT ACK"); return; } pEventMbox->CurrentState = EVENT_MBOX_STATE_IDLE; /* Build the command TxnStruct */ TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) /* Applying a CB in case of an async read */ BUILD_TTxnStruct(pTxn, ACX_REG_INTERRUPT_TRIG, &pEventMbox->iTxnGenRegSize.iRegBuffer, sizeof(pEventMbox->iTxnGenRegSize.iRegBuffer), NULL, NULL) twIf_Transact(pEventMbox->hTwif,pTxn); }
/* * \brief * * \param hFwDebug - Handle to FW Debug * \param pTxnNotUsed - Pointer to Transacton struct [Not used. Must be present due to CB compatibility] * \return none * * \par Description * This function * * \sa */ static void fwDbg_SdioValidationSM (TI_HANDLE hFwDebug, TTxnStruct* pTxnNotUsed) { TFwDebug *pFwDebug = (TFwDebug*)hFwDebug; TI_UINT8 *pWriteBuf = pFwDebug->pSdioTestWriteBuf; TI_UINT8 *pReadBuf = pFwDebug->pSdioTestReadBuf; TI_UINT32 uTxnSize = pFwDebug->uSdioTestTxnSize; TTxnStruct *pTxn = NULL; /* Used for write / read transactions */ TI_STATUS rc = TI_OK; TI_UINT32 uComparisonErrorCount = 0; /* Counts the comparison errors per iteration */ TI_UINT32 uBufIdx = 0; while(1) { switch(pFwDebug->eSdioTestState) { case FWDEBUG_SDIO_TEST_STATE_WRITE_READ: /* Write Transaction - Write data to chip */ pTxn = &pFwDebug->tSdioTestWriteTxnSt; TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) BUILD_TTxnStruct(pTxn, TWD_SDIO_VALIDATION_TXN_ADDRESS, pWriteBuf, uTxnSize, NULL, pFwDebug) /* No CB is needed here. We wait for the read operation to finish */ rc = twIf_Transact(pFwDebug->hTwif, pTxn); if(rc == TXN_STATUS_ERROR) { WLAN_OS_REPORT(("fwDbg_SdioValidationSM() - Write SDIO transaction has failed! \n")); /* Free allocated buffers */ os_memoryFree(pFwDebug->hOs, pWriteBuf, uTxnSize); os_memoryFree(pFwDebug->hOs, pReadBuf, uTxnSize); return; } /* Read Transaction - Read data from chip */ pTxn = &pFwDebug->tSdioTestReadTxnSt; TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) BUILD_TTxnStruct(pTxn, TWD_SDIO_VALIDATION_TXN_ADDRESS, pReadBuf, uTxnSize, (TTxnDoneCb)fwDbg_SdioValidationSM, pFwDebug) rc = twIf_Transact(pFwDebug->hTwif, pTxn); if(rc == TXN_STATUS_ERROR) { WLAN_OS_REPORT(("fwDbg_SdioValidationSM() - Read SDIO transaction has failed! \n")); /* Free allocated buffers */ os_memoryFree(pFwDebug->hOs, pWriteBuf, uTxnSize); os_memoryFree(pFwDebug->hOs, pReadBuf, uTxnSize); return; } /* Update state */ pFwDebug->eSdioTestState = FWDEBUG_SDIO_TEST_STATE_COMPARE; /* Updating the loop number is dove only in FWDEBUG_SDIO_TEST_STATE_COMPARE */ break; case FWDEBUG_SDIO_TEST_STATE_COMPARE: /* Compare read data to written data */ for(uBufIdx = 0; uBufIdx < uTxnSize; uBufIdx++) { if(pWriteBuf[uBufIdx] != pReadBuf[uBufIdx]) { uComparisonErrorCount++; } } /* Print error message in case of comparison error */ if(uComparisonErrorCount) { WLAN_OS_REPORT((" fwDbg_SdioValidationSM() - Found %d errors in iteration %d. \n", uComparisonErrorCount, pFwDebug->uSdioTestCurrentLoopNum)); /* Reset uComparisonErrorCount for next iterations, and set bSdioTestPassed to mark test as failed */ uComparisonErrorCount = 0; pFwDebug->bSdioTestPassed = TI_FALSE; } /* Update loop number and state */ pFwDebug->uSdioTestCurrentLoopNum++; pFwDebug->eSdioTestState = FWDEBUG_SDIO_TEST_STATE_WRITE_READ; /* If this is the last loop free allocated memory and return */ if(pFwDebug->uSdioTestCurrentLoopNum == pFwDebug->uSdioTestNumOfLoops) { if(pFwDebug->bSdioTestPassed) { WLAN_OS_REPORT(("----- SDIO Validation Test Completed ----> Passed. \n\n")); } else { WLAN_OS_REPORT(("----- SDIO Validation Test Completed ----> Failed. \n\n")); } /* Free allocated buffers */ os_memoryFree(pFwDebug->hOs, pWriteBuf, uTxnSize); os_memoryFree(pFwDebug->hOs, pReadBuf, uTxnSize); return; } break; default: WLAN_OS_REPORT(("fwDbg_SdioValidationSM() - eSdioTestState is invalid (%d) !! \n", pFwDebug->eSdioTestState)); /* Free allocated buffers */ os_memoryFree(pFwDebug->hOs, pWriteBuf, uTxnSize); os_memoryFree(pFwDebug->hOs, pReadBuf, uTxnSize); return; } /* Switch */ /* If the transactionis still pending - return. fwDbg_SdioValidationSM() will be called after transaction completion (since it is supplied as the CB function), */ if(rc == TXN_STATUS_PENDING) { return; } } /* While loop */ }
/* * \brief This function is validating the SDIO lines by write / read / compare operations. * * \param hFwDebug - Handle to FW Debug. * \param uNumOfLoops - Number of times to run the validation test. * \param uTxnSize - Size of the transaction (in bytes) to use in the validation test. * * \return TI_STATUS * * \par Description * This function is validating the SDIO lines by writing data to the chip * memory, and then reading it and compares it to the written data. * The following steps are taken: * 1. Disables ELP so the chip won't go to sleep. * 2. Disables all interrupts - This is done to disable Watchdog so no recovery will be done on the driver side. * 3. Halts the coretex. * 4. Make the read / write / compare - Most of this part is done by calling fwDbg_SdioValidationSM(). * * \sa */ TI_STATUS fwDbg_ValidateSdio(TI_HANDLE hFwDebug, TI_UINT32 uNumOfLoops, TI_UINT32 uTxnSize) { TFwDebug *pFwDebug = (TFwDebug *)hFwDebug; TI_UINT8 aDataBuffer[8] = { 'B', 'E', 'E', 'F', '4' ,'4' ,'7' ,'8' }; /* Constant data to fill in write buffer */ TI_UINT32 uWriteBufIdx = 0; /* Index in write buffer - used to fill data inside */ TTxnStruct *pTxn = &pFwDebug->tTxn; WLAN_OS_REPORT(("----- SDIO Validation Test ----> Started [Performing %d iterations of %d bytes in transaction]. \n\n", uNumOfLoops, uTxnSize)); /* Parameter range check - Make sure uTxnSize is in range */ if( (uTxnSize == 0) || (uTxnSize > TWD_SDIO_VALIDATION_TXN_SIZE_MAX) ) { WLAN_OS_REPORT(("fwDbg_ValidateSdio() - uTxnSize (%d) is out of range. Set to %d. \n", uTxnSize, TWD_SDIO_VALIDATION_TXN_SIZE_DEFAULT)); uTxnSize = TWD_SDIO_VALIDATION_TXN_SIZE_DEFAULT; } /* Parameter range check - Make sure uNumOfLoops is in range */ if(uNumOfLoops > TWD_SDIO_VALIDATION_NUM_LOOPS_MAX) { WLAN_OS_REPORT(("fwDbg_ValidateSdio() - uNumOfLoops (%d) is out of range. Set to %d. \n", uNumOfLoops, TWD_SDIO_VALIDATION_NUM_LOOPS_DEFAULT)); uNumOfLoops = TWD_SDIO_VALIDATION_NUM_LOOPS_DEFAULT; } /* 1. Disable ELP: ------------ - Call twIf_Awake() - it is not enough for disabling the ELP. - Only after the next transaction, it is promised that the chip will be awake (ELP disabled) */ twIf_Awake(pFwDebug->hTwif); /* 2. Disable all interrupts */ /* ---------------------- */ fwEvent_MaskAllFwInterrupts(pFwDebug->hFwEvent); /* 3. Halt Coretex */ /* ------------ */ pFwDebug->uSdioTestZero = 0; TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) BUILD_TTxnStruct(pTxn, ACX_REG_ECPU_CONTROL, &(pFwDebug->uSdioTestZero), REGISTER_SIZE, NULL, pFwDebug) twIf_Transact(pFwDebug->hTwif, pTxn); /* 4. Make the read / write / compare */ /* ------------------------------- */ /* Allocate memory for pFwDebug->pSdioTestWriteBuf */ pFwDebug->pSdioTestWriteBuf = (TI_UINT8 *)os_memoryAlloc(pFwDebug->hOs, uTxnSize); /* Assert Allocation */ if(NULL == pFwDebug->pSdioTestWriteBuf) { WLAN_OS_REPORT(("fwDbg_ValidateSdio() - Allocation for write buffer failed! \n")); return TI_NOK; } /* Allocate memory for pFwDebug->pSdioTestReadBuf */ pFwDebug->pSdioTestReadBuf = (TI_UINT8 *)os_memoryAlloc(pFwDebug->hOs, uTxnSize); /* Assert Allocation */ if(NULL == pFwDebug->pSdioTestReadBuf) { WLAN_OS_REPORT(("fwDbg_ValidateSdio() - Allocation for read buffer failed! \n")); /* Free pre-allocated pFwDebug->pSdioTestWriteBuf */ os_memoryFree(pFwDebug->hOs, pFwDebug->pSdioTestWriteBuf, uTxnSize); return TI_NOK; } /* Set pFwDebug struct fields */ pFwDebug->uSdioTestTxnSize = uTxnSize; pFwDebug->uSdioTestNumOfLoops = uNumOfLoops; pFwDebug->uSdioTestCurrentLoopNum = 0; pFwDebug->eSdioTestState = FWDEBUG_SDIO_TEST_STATE_WRITE_READ; pFwDebug->bSdioTestPassed = TI_TRUE; /* Fill data in pFwDebug->pSdioTestWriteBuf */ for(uWriteBufIdx = 0; uWriteBufIdx < uTxnSize; uWriteBufIdx++) { pFwDebug->pSdioTestWriteBuf[uWriteBufIdx] = aDataBuffer[uWriteBufIdx % sizeof(aDataBuffer)]; } /* Call the SM function to perform the Read / Write / Compare test */ fwDbg_SdioValidationSM(hFwDebug, NULL); return TI_OK; }