diff -r 000000000000 -r 10c42ec6c05f TWD/FW_Transfer/CmdMBox.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TWD/FW_Transfer/CmdMBox.c Tue Jun 29 12:34:26 2010 +0100 @@ -0,0 +1,552 @@ +/* + * CmdMBox.c + * + * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved. + * All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 or BSD License which accompanies + * this distribution. The Eclipse Public License is available at + * http://www.eclipse.org/legal/epl-v10.html and the BSD License is as below. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Texas Instruments nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** \file CmdMBox.c + * \brief Handle the wlan hardware command mailbox + * + * \see CmdMBox.h, CmdMBox_api.h, CmdQueue.c + */ + +#define __FILE_ID__ FILE_ID_101 +#include "tidef.h" +#include "osApi.h" +#include "timer.h" +#include "report.h" +#include "FwEvent_api.h" +#include "CmdMBox_api.h" +#include "CmdMBox.h" +#include "CmdQueue_api.h" +#include "TWDriverInternal.h" +#include "TwIf.h" + +/***************************************************************************** + ** Internal functions definitions ** + *****************************************************************************/ + +/* + * \brief Handle cmdMbox timeout. + * + * \param hCmdMbox - Handle to CmdMbox + * \return TI_OK + * + * \par Description + * Call fErrorCb() to handle the error. + * + * \sa cmdMbox_SendCommand + */ +static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured); +static void cmdMbox_ConfigHwCb (TI_HANDLE hCmdMbox, TTxnStruct *pTxn); + +/* + * \brief Create the mailbox object + * + * \param hOs - OS module object handle + * \return Handle to the created object + * + * \par Description + * Calling this function creates a CmdMbox object + * + * \sa cmdMbox_Destroy + */ +TI_HANDLE cmdMbox_Create (TI_HANDLE hOs) +{ + TCmdMbox *pCmdMbox; + TI_UINT8 CMD; + + pCmdMbox = os_memoryAlloc (hOs, sizeof (TCmdMbox),MemoryNormal); + if (pCmdMbox == NULL) + { + WLAN_OS_REPORT (("FATAL ERROR: cmdMbox_Create(): Error Creating CmdMbox - Aborting\n")); + return NULL; + } + + /* reset control module control block */ + os_memoryZero (hOs, pCmdMbox, sizeof (TCmdMbox)); + pCmdMbox->hOs = hOs; + + /* Allocate the CMD Mbox buffers and Registers buffers */ + for (CMD = 0; CMD < CMD_NUM; CMD++) + { + /* MBOX */ + pCmdMbox->aCmdTxn[CMD].pCmdMbox = os_memoryAlloc (hOs, sizeof (Command_t) + WSPI_PAD_LEN_READ,MemoryDMA); + if (pCmdMbox->aCmdTxn[CMD].pCmdMbox == NULL) + { + return NULL; + } + os_memoryZero (hOs, pCmdMbox->aCmdTxn[CMD].pCmdMbox, sizeof (Command_t) + WSPI_PAD_LEN_READ); + pCmdMbox->aCmdTxn[CMD].pCmdMbox += WSPI_PAD_LEN_READ; + /* Register */ + pCmdMbox->aRegTxn[CMD].pRegister = os_memoryAlloc (hOs, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ,MemoryDMA); + if (pCmdMbox->aRegTxn[CMD].pRegister == NULL) + { + return NULL; + } + os_memoryZero (hOs, pCmdMbox->aRegTxn[CMD].pRegister, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ); + pCmdMbox->aRegTxn[CMD].pRegister += WSPI_PAD_LEN_READ; + } + + + return pCmdMbox; +} + + +/* + * \brief Destroys the mailbox object + * + * \param hCmdMbox - The object to free + * \return TI_OK + * + * \par Description + * Calling this function destroys a CmdMbox object + * + * \sa cmdMbox_Create + */ +TI_STATUS cmdMbox_Destroy (TI_HANDLE hCmdMbox) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + TI_UINT8 CMD; + + /* free timer */ + if (pCmdMbox->hCmdMboxTimer) + { + tmr_DestroyTimer (pCmdMbox->hCmdMboxTimer); + } + + /* Free MBOX and Registers buffers */ + for (CMD = 0; CMD < CMD_NUM; CMD++) + { + if (pCmdMbox->aCmdTxn[CMD].pCmdMbox) + { + os_memoryFree (pCmdMbox->hOs, ((TI_UINT8*)(pCmdMbox->aCmdTxn[CMD].pCmdMbox)) - WSPI_PAD_LEN_READ, sizeof (Command_t) + WSPI_PAD_LEN_READ); + } + if (pCmdMbox->aRegTxn[CMD].pRegister) + { + os_memoryFree (pCmdMbox->hOs, pCmdMbox->aRegTxn[CMD].pRegister - WSPI_PAD_LEN_READ, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ); + } + } + + /* free context */ + os_memoryFree (pCmdMbox->hOs, pCmdMbox, sizeof (TCmdMbox)); + + return TI_OK; +} + + +/* + * \brief Configure the CmdMbox object + * + * \param hCmdMbox - Handle to CmdMbox + * \param hReport - Handle to report module + * \param hTwIf - Handle to TwIf + * \param hTimer - Handle to os timer + * \param hCmdQueue - Handle to CmdQueue + * \param fErrorCb - Handle to error handling function + * \return TI_OK on success or TI_NOK on failure + * + * \par Description + * + * \sa + */ +TI_STATUS cmdMbox_Init (TI_HANDLE hCmdMbox, + TI_HANDLE hReport, + TI_HANDLE hTwIf, + TI_HANDLE hTimer, + TI_HANDLE hCmdQueue, + TCmdMboxErrorCb fErrorCb) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + + pCmdMbox->hCmdQueue = hCmdQueue; + pCmdMbox->hTwIf = hTwIf; + pCmdMbox->hReport = hReport; + pCmdMbox->hCmdMboxTimer = hTimer; + + pCmdMbox->uFwAddr = 0; + pCmdMbox->uReadLen = 0; + pCmdMbox->uWriteLen = 0; + pCmdMbox->bCmdInProgress = TI_FALSE; + pCmdMbox->fErrorCb = fErrorCb; + + /* allocate OS timer memory */ + pCmdMbox->hCmdMboxTimer = tmr_CreateTimer (hTimer); + if (pCmdMbox->hCmdMboxTimer == NULL) + { + TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR, "cmdMbox_Init(): Failed to create hCmdMboxTimer!\n"); + return TI_NOK; + } + + 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].pCmdMbox)); + + + 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 = TI_OK; + 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 */ + *((TI_UINT32*)(pCmdMbox->aRegTxn[0].pRegister)) = 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].pRegister, 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 + */ +void cmdMbox_CommandComplete (TI_HANDLE hCmdMbox) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + TTxnStruct *pCmdTxn = (TTxnStruct*)&pCmdMbox->aCmdTxn[1].tTxnStruct; + Command_t *pCmd = ((Command_t *)(pCmdMbox->aCmdTxn[1].pCmdMbox)); + 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); + } +} + + +/* + * \brief Calls the cmdQueue_ResultReceived. + * + * \param hCmdMbox - Handle to CmdMbox + * \return TI_OK + * + * \par Description + * This function is called from cmdMbox_CommandComplete on a sync read, or from TwIf as a CB on an async read. + * It calls cmdQueue_ResultReceived to continue the result handling procces & switch the bCmdInProgress flag to TI_FALSE, + * meaning other commands can be sent to the FW. + * + * \sa cmdMbox_SendCommand, cmdMbox_TransferComplete + */ +TI_STATUS cmdMbox_TransferComplete(TI_HANDLE hCmdMbox) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + + /* Other commands can be sent to the FW */ + pCmdMbox->bCmdInProgress = TI_FALSE; + + cmdQueue_ResultReceived(pCmdMbox->hCmdQueue); + + return TI_OK; +} + + +/* + * \brief Handle cmdMbox timeout. + * + * \param hCmdMbox - Handle to CmdMbox + * \return TI_OK + * + * \par Description + * Call fErrorCb() to handle the error. + * + * \sa cmdMbox_SendCommand + */ +static void cmdMbox_TimeOut (TI_HANDLE hCmdMbox, TI_BOOL bTwdInitOccured) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + Command_t *pCmd = ((Command_t *)(pCmdMbox->aCmdTxn[0].pCmdMbox)); + + TRACE0(pCmdMbox->hReport, REPORT_SEVERITY_ERROR , "cmdMbox_TimeOut: Timeout occured in CmdMbox\n"); + + /* Call error CB */ + if (pCmdMbox->fErrorCb != NULL) + { + pCmdMbox->fErrorCb (pCmdMbox->hCmdQueue, + (TI_UINT32)pCmd->cmdID, + CMD_STATUS_TIMEOUT, + (void *)pCmd->parameters); + } +} + + +/* + * \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].pRegister, REGISTER_SIZE,(TTxnDoneCb)cmdMbox_ConfigHwCb, hCmdMbox) + /* Get the command mailbox address */ + rc = twIf_Transact(pCmdMbox->hTwIf, pRegTxn); + if (rc == TXN_STATUS_COMPLETE) + { + pCmdMbox->uFwAddr = *((TI_UINT32 *)(pCmdMbox->aRegTxn[1].pRegister)); + } + + return rc; +} + + +/* + * \brief Cb to cmdMbox_ConfigHw + * + * \param hCmdMbox - Handle to CmdMbox + * \return TI_OK + * + * \par Description + * + * \sa + */ +static void cmdMbox_ConfigHwCb (TI_HANDLE hCmdMbox, TTxnStruct *pTxn) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + + pCmdMbox->uFwAddr = *((TI_UINT32 *)(pCmdMbox->aRegTxn[1].pRegister)); + + /* Call back the original State Machine */ + pCmdMbox->fCb(pCmdMbox->hCb, TI_OK); +} + + +/* + * \brief Restart the module upon driver stop or restart + * + * \param hCmdMbox - Handle to CmdMbox + * \return TI_OK + * + * \par Description + * + * \sa + */ +TI_STATUS cmdMbox_Restart (TI_HANDLE hCmdMbox) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + + /* Stop the timeout timer if running and reset the state */ + tmr_StopTimer (pCmdMbox->hCmdMboxTimer); + pCmdMbox->bCmdInProgress = TI_FALSE; + pCmdMbox->uReadLen = 0; + pCmdMbox->uWriteLen = 0; + + return TI_OK; +} + + +/* + * \brief Return the latest command status + * + * \param hCmdMbox - Handle to CmdMbox + * \return TI_OK or TI_NOK + * + * \par Description + * + * \sa + */ +TI_STATUS cmdMbox_GetStatus (TI_HANDLE hCmdMbox) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + Command_t *pCmd = ((Command_t *)(pCmdMbox->aCmdTxn[1].pCmdMbox)); + TI_STATUS status; + + status = (pCmd->cmdStatus == CMD_STATUS_SUCCESS) ? TI_OK : TI_NOK; + TRACE2(pCmdMbox->hReport, REPORT_SEVERITY_INFORMATION , "cmdMbox_GetStatus: TI_STATUS = (%d) <= pCmdMbox->pCmdMbox.cmdStatus = %d\n", status, pCmd->cmdStatus); + return status; +} + + +/* + * \brief Return the MBox address + * + * \param hCmdMbox - Handle to CmdMbox + * \return MBox address + * + * \par Description + * + * \sa + */ +TI_UINT32 cmdMbox_GetMboxAddress (TI_HANDLE hCmdMbox) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + + return pCmdMbox->uFwAddr; +} + + +/* + * \brief Return the Command parameters buffer + * + * \param hCmdMbox - Handle to CmdMbox + * \param pParamBuf - Holds the returned buffer + * \return + * + * \par Description + * Copying the command's data to pParamBuf + * + * \sa + */ +void cmdMbox_GetCmdParams (TI_HANDLE hCmdMbox, TI_UINT8* pParamBuf) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + Command_t *pCmd = ((Command_t *)(pCmdMbox->aCmdTxn[1].pCmdMbox)); + + /* + * Copy the results to the caller buffer: + * We need to copy only the data without the cmdMbox header, + * otherwise we will overflow the pParambuf + */ + os_memoryCopy (pCmdMbox->hOs, + (void *)pParamBuf, + (void *)pCmd->parameters, + pCmdMbox->uReadLen - CMDMBOX_HEADER_LEN); + +} + + +#ifdef TI_DBG + +void cmdMbox_PrintInfo(TI_HANDLE hCmdMbox) +{ + TCmdMbox *pCmdMbox = (TCmdMbox *)hCmdMbox; + + WLAN_OS_REPORT(("Print cmdMbox module info\n")); + WLAN_OS_REPORT(("=========================\n")); + WLAN_OS_REPORT(("bCmdInProgress = %d\n", pCmdMbox->bCmdInProgress)); +} + +#endif /* TI_DBG */ + +