/* * \brief Config the FwEvent module object * * \param hFwEvent - FwEvent Driver handle * \param hTWD - Handle to TWD module * \return TI_OK * * \par Description * From hTWD we extract : hOs, hReport, hTwIf, hContext, * hHealthMonitor, hEventMbox, hCmdMbox, hRxXfer, * hTxHwQueue, hTxResult * In this function we also register the FwEvent to the context engine * * \sa */ TI_STATUS fwEvent_Init (TI_HANDLE hFwEvent, TI_HANDLE hTWD) { TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; TTwd *pTWD = (TTwd *)hTWD; TTxnStruct* pTxn; pFwEvent->hTWD = hTWD; pFwEvent->hOs = pTWD->hOs; pFwEvent->hReport = pTWD->hReport; pFwEvent->hContext = pTWD->hContext; pFwEvent->hTwIf = pTWD->hTwIf; pFwEvent->hHealthMonitor = pTWD->hHealthMonitor; pFwEvent->hEventMbox = pTWD->hEventMbox; pFwEvent->hCmdMbox = pTWD->hCmdMbox; pFwEvent->hRxXfer = pTWD->hRxXfer; pFwEvent->hTxHwQueue = pTWD->hTxHwQueue; pFwEvent->hTxXfer = pTWD->hTxXfer; pFwEvent->hTxResult = pTWD->hTxResult; pFwEvent->eSmState = FWEVENT_STATE_IDLE; pFwEvent->bIntrPending = TI_FALSE; pFwEvent->uNumPendHndlrs = 0; pFwEvent->uEventMask = 0; pFwEvent->uEventVector = 0; /* Prepare Interrupts Mask regiter Txn structure */ /* * Note!!: The mask transaction is sent in low priority because it is used in the * init process which includes a long sequence of low priority transactions, * and the order of this sequence is important so we must use the same priority */ pTxn = (TTxnStruct*)&pFwEvent->tMaskTxn.tTxnStruct; TXN_PARAM_SET(pTxn, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) BUILD_TTxnStruct(pTxn, HINT_MASK, &pFwEvent->tMaskTxn.uData, REGISTER_SIZE, NULL, NULL) /* Prepare FW status Txn structure (includes 4 bytes interrupt status reg and 64 bytes FW-status from memory area) */ /* Note: This is the only transaction that is sent in high priority. * The original reason was to lower the interrupt latency, but we may consider using the * same priority as all other transaction for simplicity. */ pTxn = (TTxnStruct*)&pFwEvent->tFwStatusTxn.tTxnStruct; TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) BUILD_TTxnStruct(pTxn, FW_STATUS_ADDR, &pFwEvent->tFwStatusTxn.tFwStatus, sizeof(FwStatus_t), (TTxnDoneCb)fwEvent_StateMachine, hFwEvent) /* * Register the FwEvent to the context engine and get the client ID. * The FwEvent() will be called from the context_DriverTask() after scheduled * by a FW-Interrupt (see fwEvent_InterruptRequest()). */ pFwEvent->uContextId = context_RegisterClient (pFwEvent->hContext, fwEvent_NewEvent, hFwEvent, TI_FALSE, "FW_EVENT", sizeof("FW_EVENT")); return TI_OK; }
/* * \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 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; }
/** * \fn ifSlpMng_Init * \brief Interface Sleep Manager object initialization * */ EMcpfRes ifSlpMng_Init (handle_t hIfSlpMng, const handle_t hTxnQ, const handle_t hBusDrv, const McpU32 uFuncId, const McpHalChipId tChipId, const McpHalTranId tTransId) { TifSlpMngObj * pIfSlpMng = (TifSlpMngObj *) hIfSlpMng; McpHalPmHandler pmHandler = {pmEventHandler}; pIfSlpMng->hTxnQ = hTxnQ; /* Transaction queue handle */ pIfSlpMng->hBusDrv = hBusDrv; /* Bus driver handle */ pIfSlpMng->uFuncId = uFuncId; /* Transaction queue function id */ pIfSlpMng->tChipId = tChipId; /* PM chip id for power management */ pIfSlpMng->tTransId = tTransId; /* PM transport layer id for power management */ /* Build Sleep Management transaction */ TXN_PARAM_SET (pIfSlpMng->pMngTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_CTRL, TXN_DIRECTION_WRITE, 0); BUILD_TTxnStruct (pIfSlpMng->pMngTxn, 0, NULL, 0, NULL, NULL); TXN_PARAM_SET_SINGLE_STEP(pIfSlpMng->pMngTxn, 1); /* Sleep Management transaction is always single step */ pIfSlpMng->eState = IFSLPMNG_STATE_AWAKE; MCP_HAL_PM_RegisterTransport (pIfSlpMng->tChipId, pIfSlpMng->tTransId, &pmHandler); return RES_OK; }
/* * \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; }
/* * \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; }
/* * \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); }
void twIf_SetPartition(TI_HANDLE hTwIf, TPartition * pPartition) { TTwIfObj *pTwIf = (TTwIfObj *) hTwIf; TPartitionRegTxn *pPartitionRegTxn; /* The partition transaction structure for one register */ TTxnStruct *pTxnHdr; /* The partition transaction header (as used in the TxnQ API) */ ETxnStatus eStatus; int i; /* Save partition information for translation and validation. */ pTwIf->uMemAddr1 = pPartition[0].uMemAdrr; pTwIf->uMemSize1 = pPartition[0].uMemSize; pTwIf->uMemAddr2 = pPartition[1].uMemAdrr; pTwIf->uMemSize2 = pPartition[1].uMemSize; pTwIf->uMemAddr3 = pPartition[2].uMemAdrr; pTwIf->uMemSize3 = pPartition[2].uMemSize; pTwIf->uMemAddr4 = pPartition[3].uMemAdrr; /* Allocate memory for the current 4 partition transactions */ pPartitionRegTxn = (TPartitionRegTxn *) os_memoryAlloc(pTwIf->hOs, 7 * sizeof(TPartitionRegTxn)); pTxnHdr = &(pPartitionRegTxn->tHdr); /* Zero the allocated memory to be certain that unused fields will be initialized */ os_memoryZero(pTwIf->hOs, pPartitionRegTxn, 7 * sizeof(TPartitionRegTxn)); /* Prepare partition transaction data */ pPartitionRegTxn[0].tData = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr1); pPartitionRegTxn[1].tData = ENDIAN_HANDLE_LONG(pTwIf->uMemSize1); pPartitionRegTxn[2].tData = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr2); pPartitionRegTxn[3].tData = ENDIAN_HANDLE_LONG(pTwIf->uMemSize2); pPartitionRegTxn[4].tData = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr3); pPartitionRegTxn[5].tData = ENDIAN_HANDLE_LONG(pTwIf->uMemSize3); pPartitionRegTxn[6].tData = ENDIAN_HANDLE_LONG(pTwIf->uMemAddr4); /* Prepare partition Txn header */ for (i = 0; i < 7; i++) { pTxnHdr = &(pPartitionRegTxn[i].tHdr); TXN_PARAM_SET(pTxnHdr, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) TXN_PARAM_SET_MORE(pTxnHdr, 1); TXN_PARAM_SET_SINGLE_STEP(pTxnHdr, 0); } /* Memory address */ pTxnHdr = &(pPartitionRegTxn[0].tHdr); BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR + 4, &(pPartitionRegTxn[0].tData), REGISTER_SIZE, 0, 0) twIf_SendTransaction(pTwIf, pTxnHdr); /* Memory size */ pTxnHdr = &(pPartitionRegTxn[1].tHdr); BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR + 0, &(pPartitionRegTxn[1].tData), REGISTER_SIZE, 0, 0) twIf_SendTransaction(pTwIf, pTxnHdr); /* Registers address */ pTxnHdr = &(pPartitionRegTxn[2].tHdr); BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR + 12, &(pPartitionRegTxn[2].tData), REGISTER_SIZE, 0, 0) twIf_SendTransaction(pTwIf, pTxnHdr); /* Registers size */ pTxnHdr = &(pPartitionRegTxn[3].tHdr); BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR + 8, &(pPartitionRegTxn[3].tData), REGISTER_SIZE, 0, 0) eStatus = twIf_SendTransaction(pTwIf, pTxnHdr); /* Registers address */ pTxnHdr = &(pPartitionRegTxn[4].tHdr); BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR + 20, &(pPartitionRegTxn[4].tData), REGISTER_SIZE, 0, 0) twIf_SendTransaction(pTwIf, pTxnHdr); /* Registers size */ pTxnHdr = &(pPartitionRegTxn[5].tHdr); BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR + 16, &(pPartitionRegTxn[5].tData), REGISTER_SIZE, 0, 0) eStatus = twIf_SendTransaction(pTwIf, pTxnHdr); /* Registers address */ pTxnHdr = &(pPartitionRegTxn[6].tHdr); BUILD_TTxnStruct(pTxnHdr, PARTITION_REGISTERS_ADDR + 24, &(pPartitionRegTxn[6].tData), REGISTER_SIZE, twIf_PartitionTxnDoneCb, pTwIf) twIf_SendTransaction(pTwIf, pTxnHdr); /* If the transaction is done, free the allocated memory (otherwise freed in the partition CB) */ if (eStatus != TXN_STATUS_PENDING) { os_memoryFree(pTwIf->hOs, pPartitionRegTxn, 7 * sizeof(TPartitionRegTxn)); } }
/** * \fn twIf_Init * \brief Init module * * - Init required handles and module variables * - Create the TxnDone-queue * - Register to TxnQ * - Register to context module * * \note * \param hTwIf - The module's object * \param hXxx - Handles to other modules * \param fRecoveryCb - Callback function for recovery completed after TxnDone * \param hRecoveryCb - Handle for fRecoveryCb * \return void * \sa */ void twIf_Init(TI_HANDLE hTwIf, TI_HANDLE hReport, TI_HANDLE hContext, TI_HANDLE hTimer, TI_HANDLE hTxnQ, TRecoveryCb fRecoveryCb, TI_HANDLE hRecoveryCb) { TTwIfObj *pTwIf = (TTwIfObj *) hTwIf; TI_UINT32 uNodeHeaderOffset; TTxnStruct *pTxnHdr; /* The ELP transactions header (as used in the TxnQ API) */ pTwIf->hReport = hReport; pTwIf->hContext = hContext; pTwIf->hTimer = hTimer; pTwIf->hTxnQ = hTxnQ; pTwIf->fRecoveryCb = fRecoveryCb; pTwIf->hRecoveryCb = hRecoveryCb; /* Prepare ELP sleep transaction */ pTwIf->tElpTxnSleep.uElpData = ELP_CTRL_REG_SLEEP; pTxnHdr = &(pTwIf->tElpTxnSleep.tHdr); TXN_PARAM_SET(pTxnHdr, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) TXN_PARAM_SET_MORE(pTxnHdr, 0); /* Sleep is the last transaction! */ /* NOTE: Function id for single step will be replaced to 0 by the bus driver */ TXN_PARAM_SET_SINGLE_STEP(pTxnHdr, 1); /* ELP write is always single step (TxnQ is topped)! */ BUILD_TTxnStruct(pTxnHdr, ELP_CTRL_REG_ADDR, &(pTwIf->tElpTxnSleep.uElpData), sizeof(TI_UINT8), NULL, NULL) /* Prepare ELP awake transaction */ pTwIf->tElpTxnAwake.uElpData = ELP_CTRL_REG_AWAKE; pTxnHdr = &(pTwIf->tElpTxnAwake.tHdr); TXN_PARAM_SET(pTxnHdr, TXN_LOW_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) TXN_PARAM_SET_MORE(pTxnHdr, 1); /* NOTE: Function id for single step will be replaced to 0 by the bus driver */ TXN_PARAM_SET_SINGLE_STEP(pTxnHdr, 1); /* ELP write is always single step (TxnQ is topped)! */ BUILD_TTxnStruct(pTxnHdr, ELP_CTRL_REG_ADDR, &(pTwIf->tElpTxnAwake.uElpData), sizeof(TI_UINT8), NULL, NULL) /* Create the TxnDone queue. */ uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode); pTwIf->hTxnDoneQueue = que_Create(pTwIf->hOs, pTwIf->hReport, TXN_DONE_QUE_SIZE, uNodeHeaderOffset); if (pTwIf->hTxnDoneQueue == NULL) { TRACE0(pTwIf->hReport, REPORT_SEVERITY_ERROR, "twIf_Init: TxnDone queue creation failed!\n"); } /* Register to the context engine and get the client ID */ pTwIf->uContextId = context_RegisterClient(pTwIf->hContext, twIf_HandleTxnDone, hTwIf, TI_TRUE, "TWIF", sizeof("TWIF")); /* Allocate timer */ pTwIf->hPendRestartTimer = tmr_CreateTimer(hTimer); if (pTwIf->hPendRestartTimer == NULL) { TRACE0(pTwIf->hReport, REPORT_SEVERITY_ERROR, "twIf_Init: Failed to create PendRestartTimer!\n"); return; } pTwIf->bPendRestartTimerRunning = TI_FALSE; /* Register to TxnQ */ txnQ_Open(pTwIf->hTxnQ, TXN_FUNC_ID_WLAN, TXN_NUM_PRIORITYS, (TTxnQueueDoneCb) twIf_TxnDoneCb, hTwIf); /* Restart TwIf and TxnQ modules */ twIf_Restart(hTwIf); }
/* * \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; }