TI_STATUS TWD_InitHw (TI_HANDLE hTWD, TI_UINT8 *pbuf, TI_UINT32 length, TI_UINT32 uRxDmaBufLen, TI_UINT32 uTxDmaBufLen) { TTwd *pTWD = (TTwd *)hTWD; TI_STATUS eStatus; /* Provide bus related parameters to Xfer modules before any usage of the bus! */ rxXfer_SetBusParams (pTWD->hRxXfer, uRxDmaBufLen); txXfer_SetBusParams (pTWD->hTxXfer, uTxDmaBufLen); hwInit_SetNvsImage (pTWD->hHwInit, pbuf, length); /* * Update the TwIf that the HW is awake * This will protect the initialization process from going to sleep * After the firmware initializations completed (TWD_EnableExternalEvents), the sleep will be enabled */ twIf_Awake (pTWD->hTwIf); twIf_HwAvailable (pTWD->hTwIf); /* This initiates the HW init sequence */ eStatus = hwInit_Boot(pTWD->hHwInit); if (eStatus == TXN_STATUS_ERROR) { return TI_NOK; } return TI_OK; }
/* * \brief FW-Event state machine * * \param hFwEvent - FwEvent Driver handle * \return void * * \par Description * * Process the current FW events in a sequence that may progress in the same context, * or exit if pending an Async transaction, which will call back the SM when finished. * * \sa */ static void fwEvent_StateMachine (TfwEvent *pFwEvent) { ETxnStatus eStatus = TXN_STATUS_ERROR; /* Set to error to detect if used uninitialized */ CL_TRACE_START_L3(); /* * Loop through the states sequence as long as the process is synchronous. * Exit when finished or if an Asynchronous process is required. * In this case the SM will be called back upon Async operation completion. */ while (1) { switch (pFwEvent->eSmState) { /* IDLE: Update TwIf and read interrupt info from FW */ case FWEVENT_STATE_IDLE: { CL_TRACE_START_L5(); twIf_Awake(pFwEvent->hTwIf); eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".ReadInfo"); break; } /* WAIT_INTR_INFO: We have the interrupt info so call the handlers accordingly */ case FWEVENT_STATE_WAIT_INTR_INFO: { CL_TRACE_START_L5(); eStatus = fwEvent_SmHandleEvents (pFwEvent); /* If state was changed to IDLE by recovery or stop process, exit (process terminated) */ if (pFwEvent->eSmState == FWEVENT_STATE_IDLE) { CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); return; } pFwEvent->eSmState = FWEVENT_STATE_WAIT_HANDLE_COMPLT; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlEvents"); break; } /* WAIT_HANDLE_COMPLT: Current handling is completed. */ case FWEVENT_STATE_WAIT_HANDLE_COMPLT: { /* If pending interrupt, read interrupt info (back to WAIT_INTR_INFO state) */ if (pFwEvent->bIntrPending) { CL_TRACE_START_L5(); pFwEvent->bIntrPending = TI_FALSE; eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; CL_TRACE_END_L5("tiwlan_drv.ko", "CONTEXT", "FwEvent", ".HndlCmplt"); } /* Else - all done so release TwIf to sleep and exit */ else { twIf_Sleep(pFwEvent->hTwIf); pFwEvent->eSmState = FWEVENT_STATE_IDLE; TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: Completed, NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); /**** Finished all current events handling so exit ****/ return; } break; } } /* switch */ TRACE3(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending); /* If last status is Pending, exit the SM (to be called back upon Async operation completion) */ if (eStatus == TXN_STATUS_PENDING) { CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); return; } /* If error occured, stop the process and exit (should be cleaned by recovery process) */ else if (eStatus == TXN_STATUS_ERROR) { TRACE5(pFwEvent->hReport, REPORT_SEVERITY_ERROR, "fwEvent_StateMachine: NewState=%d, Status=%d, IntrPending=%d, EventVector=0x%x, EventMask=0x%x\n", pFwEvent->eSmState, eStatus, pFwEvent->bIntrPending, pFwEvent->uEventVector, pFwEvent->uEventMask); CL_TRACE_END_L3("tiwlan_drv.ko", "CONTEXT", "FwEvent", ""); fwEvent_Stop ((TI_HANDLE)pFwEvent); return; } /* If we got here the status is COMPLETE so continue in the while loop to the next state */ } /* while */ }
/* * \brief Configure the CmdQueue object * * \param hCmdQueue - Handle to CmdQueue * \param eCmdQueueEvent - The event that triggered the SM * \return TI_OK on success or TI_NOK on failure * * \par Description * Handles the CmdQueue SM. * * \sa cmdQueue_Push, cmdQueue_ResultReceived */ static TI_STATUS cmdQueue_SM (TI_HANDLE hCmdQueue, ECmdQueueSmEvents eCmdQueueEvent) { TCmdQueue *pCmdQueue = (TCmdQueue*)hCmdQueue; TI_BOOL bBreakWhile = TI_FALSE; TI_STATUS rc = TI_OK, status; TCmdQueueNode *pHead; TI_UINT32 uReadLen, uWriteLen; while(!bBreakWhile) { switch (pCmdQueue->state) { case CMDQUEUE_STATE_IDLE: switch(eCmdQueueEvent) { case CMDQUEUE_EVENT_RUN: pCmdQueue->state = CMDQUEUE_STATE_WAIT_FOR_COMPLETION; pHead = &pCmdQueue->aCmdQueue[pCmdQueue->head]; #ifdef CMDQUEUE_DEBUG_PRINT TRACE4(pCmdQueue->hReport, REPORT_SEVERITY_CONSOLE, "cmdQueue_SM: Send Cmd: CmdType = %d(%d) Len = %d, NumOfCmd = %d", pHead->cmdType, (pHead->aParamsBuf) ? *(TI_UINT16 *)pHead->aParamsBuf:0, pHead->uParamsLen, pCmdQueue->uNumberOfCommandInQueue); WLAN_OS_REPORT(("cmdQueue_SM: Send Cmd: CmdType = %s(%s)\n" "Len = %d, NumOfCmd = %d \n", cmdQueue_GetCmdString(pHead->cmdType), (pHead->aParamsBuf) ? cmdQueue_GetIEString(pHead->cmdType,*(TI_UINT16 *)pHead->aParamsBuf):"", pHead->uParamsLen, pCmdQueue->uNumberOfCommandInQueue)); #endif #ifdef TI_DBG pCmdQueue->uCmdSendCounter++; #endif /* * if bAwake is true, then we reached here because there were more commands * in the queue after sending a previous command. * There is no need to send another awake command to TwIf. */ if (pCmdQueue->bAwake == TI_FALSE) { /* Keep the device awake for the entire Cmd transaction */ twIf_Awake(pCmdQueue->hTwIf); pCmdQueue->bAwake = TI_TRUE; } if (pHead->cmdType == CMD_INTERROGATE) { uWriteLen = CMDQUEUE_INFO_ELEM_HEADER_LEN; /* Will be updated by CmdMbox to count the status response */ uReadLen = pHead->uParamsLen; } else if(pHead->cmdType == CMD_TEST) { /* CMD_TEST has configure & interrogate abillities together */ uWriteLen = pHead->uParamsLen; /* Will be updated by CmdMbox to count the status response */ uReadLen = pHead->uParamsLen; } else if (pHead->cmdType == CMD_NOP) { /* NOP command is used for synchronizaiton purpose only, no FW transaction */ eCmdQueueEvent = CMDQUEUE_EVENT_COMPLETE; break; } else /* CMD_CONFIGURE or others */ { uWriteLen = pHead->uParamsLen; /* Will be updated by CmdMbox to count the status response */ uReadLen = 0; } /* send the command to TNET */ rc = cmdMbox_SendCommand (pCmdQueue->hCmdMBox, pHead->cmdType, pHead->aParamsBuf, uWriteLen, uReadLen); bBreakWhile = TI_TRUE; /* end of CMDQUEUE_EVENT_RUN */ break; default: TRACE1(pCmdQueue->hReport, REPORT_SEVERITY_ERROR, "cmdQueue_SM: ** ERROR ** No such event (%d) for state CMDQUEUE_STATE_IDLE\n",eCmdQueueEvent); bBreakWhile = TI_TRUE; rc = TI_NOK; break; } break; case CMDQUEUE_STATE_WAIT_FOR_COMPLETION: switch(eCmdQueueEvent) { case CMDQUEUE_EVENT_RUN: /* We are in the middle of other command transaction so there is nothing top be done */ bBreakWhile = TI_TRUE; rc = TXN_STATUS_PENDING; break; case CMDQUEUE_EVENT_COMPLETE: { Command_e cmdType; TI_UINT16 uParam; void *fCb, *hCb, *pCb; CommandStatus_e cmdStatus; pHead = &pCmdQueue->aCmdQueue[pCmdQueue->head]; /* Keep callback parameters in temporary variables */ cmdType = pHead->cmdType; uParam = *(TI_UINT16 *)pHead->aParamsBuf; fCb = pHead->fCb; hCb = pHead->hCb; pCb = pHead->pInterrogateBuf; /* * Delete the command from the queue before calling a callback * because there may be nested calls inside a callback */ pCmdQueue->head ++; if (pCmdQueue->head >= CMDQUEUE_QUEUE_DEPTH) pCmdQueue->head = 0; pCmdQueue->uNumberOfCommandInQueue --; #ifdef TI_DBG pCmdQueue->uCmdCompltCounter++; #endif /* Read the latest command return status */ if (pHead->cmdType != CMD_NOP) { status = cmdMbox_GetStatus (pCmdQueue->hCmdMBox, &cmdStatus); } else { /* NOP command is used for synchronizaiton purpose only, no FW transaction */ status = TI_OK; } if (status != TI_OK) { if (cmdStatus == CMD_STATUS_REJECT_MEAS_SG_ACTIVE) { /* return reject status in the callback */ status = SG_REJECT_MEAS_SG_ACTIVE; pCmdQueue->bErrorFlag = TI_FALSE; } else { WLAN_OS_REPORT(("cmdQueue_SM: ** ERROR ** Mbox status error %d, set bErrorFlag !!!!!\n", cmdStatus)); TRACE1(pCmdQueue->hReport, REPORT_SEVERITY_ERROR, "cmdQueue_SM: ** ERROR ** Mbox status error %d, set bErrorFlag !!!!!\n", cmdStatus); pCmdQueue->bErrorFlag = TI_TRUE; } } else { pCmdQueue->bErrorFlag = TI_FALSE; } /* If the command had a CB, then call it with the proper results buffer */ if (fCb) { if (pCb) { /* If pInterrogateBuf isn't NULL we need to copy the results */ cmdMbox_GetCmdParams(pCmdQueue->hCmdMBox, pCb); /* Call the CB with the result buffer and the returned status */ ((TCmdQueueInterrogateCb)fCb) (hCb, status, pCb); } else { /* Call the CB with only the returned status */ ((TCmdQueueCb)fCb) (hCb, status); } } else { /* Call the generic callback */ if (pCmdQueue->fCmdCompleteCb) { pCmdQueue->fCmdCompleteCb (pCmdQueue->hCmdCompleteCb, cmdType, uParam, status); } } /* Check if there are any more commands in queue */ if (pCmdQueue->uNumberOfCommandInQueue > 0) { /* If queue isn't empty, send the next command */ pCmdQueue->state = CMDQUEUE_STATE_IDLE; eCmdQueueEvent = CMDQUEUE_EVENT_RUN; } else { /* If queue is empty, we can permit TwIf to send sleep a command if neccesary */ twIf_Sleep(pCmdQueue->hTwIf); pCmdQueue->bAwake = TI_FALSE; pCmdQueue->state = CMDQUEUE_STATE_IDLE; bBreakWhile = TI_TRUE; } /* end of CMDQUEUE_EVENT_COMPLETE */ } break; default: TRACE1(pCmdQueue->hReport, REPORT_SEVERITY_ERROR, "cmdQueue_SM: ** ERROR ** No such event (%d) for state CMDQUEUE_STATE_IDLE\n",eCmdQueueEvent); bBreakWhile = TI_TRUE; rc = TI_NOK; break; /* end of switch event */ } break; /* end of switch state */ } /* end of while */ } return rc; }
/* * \brief FW-Event state machine * * \param hFwEvent - FwEvent Driver handle * \return void * * \par Description * * Process the current FW events in a sequence that may progress in the same context, * or exit if pending an Async transaction, which will call back the SM when finished. * * \sa */ static void fwEvent_StateMachine (TfwEvent *pFwEvent) { ETxnStatus eStatus = TXN_STATUS_ERROR; /* Set to error to detect if used uninitialized */ /* * Loop through the states sequence as long as the process is synchronous. * Exit when finished or if an Asynchronous process is required. * In this case the SM will be called back upon Async operation completion. */ while (1) { switch (pFwEvent->eSmState) { /* IDLE: Update TwIf and read interrupt info from FW */ case FWEVENT_STATE_IDLE: { twIf_Awake(pFwEvent->hTwIf); eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; break; } /* WAIT_INTR_INFO: We have the interrupt info so call the handlers accordingly */ case FWEVENT_STATE_WAIT_INTR_INFO: { eStatus = fwEvent_SmHandleEvents (pFwEvent); /* If state was changed to IDLE by recovery or stop process, exit (process terminated) */ if (pFwEvent->eSmState == FWEVENT_STATE_IDLE) { return; } pFwEvent->eSmState = FWEVENT_STATE_WAIT_HANDLE_COMPLT; break; } /* WAIT_HANDLE_COMPLT: Current handling is completed. */ case FWEVENT_STATE_WAIT_HANDLE_COMPLT: { /* If pending interrupt, read interrupt info (back to WAIT_INTR_INFO state) */ if (pFwEvent->bIntrPending) { pFwEvent->bIntrPending = TI_FALSE; eStatus = fwEvent_SmReadIntrInfo (pFwEvent); pFwEvent->eSmState = FWEVENT_STATE_WAIT_INTR_INFO; } /* Else - all done so release TwIf to sleep and exit */ else { twIf_Sleep(pFwEvent->hTwIf); pFwEvent->eSmState = FWEVENT_STATE_IDLE; /**** Finished all current events handling so exit ****/ return; } break; } } /* switch */ /* If last status is Pending, exit the SM (to be called back upon Async operation completion) */ if (eStatus == TXN_STATUS_PENDING) { return; } /* If error occured, stop the process and exit (should be cleaned by recovery process) */ else if (eStatus == TXN_STATUS_ERROR) { fwEvent_Stop ((TI_HANDLE)pFwEvent); return; } /* If we got here the status is COMPLETE so continue in the while loop to the next state */ } /* while */ }
/* * \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; }