diff -r 000000000000 -r 10c42ec6c05f TWD/FW_Transfer/FwEvent.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TWD/FW_Transfer/FwEvent.c Tue Jun 29 12:34:26 2010 +0100 @@ -0,0 +1,738 @@ +/* + * FwEvent.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 FwEvent.c + * \brief Handle firmware events + * + * + * \par Description + * Call the appropriate event handler. + * + * \see FwEvent.h + */ + +#define __FILE_ID__ FILE_ID_104 +#include "tidef.h" +#include "report.h" +#include "context.h" +#include "osApi.h" +#include "TWDriver.h" +#include "TWDriverInternal.h" +#include "FwEvent.h" +#include "txResult_api.h" +#include "CmdMBox_api.h" +#include "rxXfer_api.h" +#include "txXfer_api.h" +#include "txHwQueue_api.h" +#include "eventMbox_api.h" +#include "TwIf.h" +#ifdef TI_DBG + #include "tracebuf_api.h" +#endif + +#ifdef _VLCT_ +extern int trigger_another_read; +#endif + +#define USE_SDIO_24M_WORKAROUND +#define FW_STATUS_MEM_ADDRESS 0x40400 + + +#define TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent) pFwEvent->tMaskTxn.tTxnStruct.uHwAddr = HINT_MASK; +#define TXN_FW_EVENT_SET_UNMASK_ADDR(pFwEvent) pFwEvent->tUnMaskTxn.tTxnStruct.uHwAddr = HINT_MASK; +#define TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent) pFwEvent->tFwStatusTxn.tTxnStruct.uHwAddr = ACX_REG_INTERRUPT_CLEAR; +#define TXN_FW_EVENT_SET_FW_MEM_ADDR(pFwEvent) pFwEvent->tMemFwStatusTxn.tTxnStruct.uHwAddr = FW_STATUS_MEM_ADDRESS; +/********************* static function declerations *************************/ + +/* + * \brief Call FwEvent client's event handler + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * + * \sa fwEvent_ReadCompleteCb + */ +static void fwEvent_CallHandler (TI_HANDLE hFwEvent); + + +/* + * \brief Create the FwEvent module object + * + * \param hOs - OS module object handle + * \return Handle to the created object + * + * \par Description + * Calling this function creates a FwEvent object + * + * \sa fwEvent_Destroy + */ +TI_HANDLE fwEvent_Create (TI_HANDLE hOs) +{ + TfwEvent *pFwEvent; + + pFwEvent = os_memoryAlloc (hOs, sizeof(TfwEvent),MemoryNormal); + if (pFwEvent == NULL) + { + return NULL; + } + + os_memoryZero (hOs, pFwEvent, sizeof(TfwEvent)); + + /* Allocation of Data */ + pFwEvent->tMaskTxn.pData = os_memoryAlloc (hOs, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ,MemoryDMA); + if (pFwEvent->tMaskTxn.pData == NULL) + { + return NULL; + } + os_memoryZero (hOs, pFwEvent->tMaskTxn.pData, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ); + pFwEvent->tMaskTxn.pData += WSPI_PAD_LEN_READ; + + /* Allocation of Data */ + pFwEvent->tUnMaskTxn.pData = os_memoryAlloc (hOs, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ,MemoryDMA); + if (pFwEvent->tUnMaskTxn.pData == NULL) + { + return NULL; + } + os_memoryZero (hOs, pFwEvent->tUnMaskTxn.pData, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ); + pFwEvent->tUnMaskTxn.pData += WSPI_PAD_LEN_READ; + + /* Allocation of FW Status buffer */ + pFwEvent->tFwStatusTxn.pFwStatus = os_memoryAlloc (hOs, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ,MemoryDMA); + if (pFwEvent->tFwStatusTxn.pFwStatus == NULL) + { + return NULL; + } + os_memoryZero (hOs, pFwEvent->tFwStatusTxn.pFwStatus, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ); + pFwEvent->tFwStatusTxn.pFwStatus += WSPI_PAD_LEN_READ; + + /* Allocation of FW Status buffer */ + pFwEvent->tMemFwStatusTxn.pFwStatus = os_memoryAlloc (hOs, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ,MemoryDMA); + if (pFwEvent->tMemFwStatusTxn.pFwStatus == NULL) + { + return NULL; + } + os_memoryZero (hOs, pFwEvent->tMemFwStatusTxn.pFwStatus, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ); + pFwEvent->tMemFwStatusTxn.pFwStatus += WSPI_PAD_LEN_READ; + + + pFwEvent->hOs = hOs; + + return (TI_HANDLE)pFwEvent; +} + + +/* + * \brief Destroys the FwEvent object + * + * \param hFwEvent - The object to free + * \return TI_OK + * + * \par Description + * Calling this function destroys a FwEvent object + * + * \sa fwEvent_Create + */ +TI_STATUS fwEvent_Destroy (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + if (pFwEvent->tMaskTxn.pData) + { + os_memoryFree (pFwEvent->hOs, pFwEvent->tMaskTxn.pData - WSPI_PAD_LEN_READ, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ); + } + + if (pFwEvent->tUnMaskTxn.pData) + { + os_memoryFree (pFwEvent->hOs, pFwEvent->tUnMaskTxn.pData - WSPI_PAD_LEN_READ, sizeof (TI_UINT32) + WSPI_PAD_LEN_READ); + } + + if (pFwEvent->tFwStatusTxn.pFwStatus) + { + os_memoryFree (pFwEvent->hOs, pFwEvent->tFwStatusTxn.pFwStatus - WSPI_PAD_LEN_READ, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ); + } + + if (pFwEvent->tMemFwStatusTxn.pFwStatus) + { + os_memoryFree (pFwEvent->hOs, pFwEvent->tMemFwStatusTxn.pFwStatus - WSPI_PAD_LEN_READ, sizeof (FwStatus_t) + WSPI_PAD_LEN_READ); + } + + if (pFwEvent) + { + os_memoryFree (pFwEvent->hOs, pFwEvent, sizeof(TfwEvent)); + } + + return TI_OK; +} + + +/* + * \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->eFwEventState = FW_EVENT_STATE_IDLE; + pFwEvent->uEventMask = 0; + pFwEvent->uEventVector = 0; + pFwEvent->bFwNotificationFlag = TI_FALSE; + + pTxn = (TTxnStruct*)&pFwEvent->tMaskTxn.tTxnStruct; + TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) + BUILD_TTxnStruct(pTxn, HINT_MASK, pFwEvent->tMaskTxn.pData, REGISTER_SIZE, NULL, NULL) + + pTxn = (TTxnStruct*)&pFwEvent->tUnMaskTxn.tTxnStruct; + TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_WRITE, TXN_INC_ADDR) + BUILD_TTxnStruct(pTxn, HINT_MASK, pFwEvent->tUnMaskTxn.pData, REGISTER_SIZE, NULL, NULL) + +#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */ + /* First txn is HINT_STT_CLR register */ + 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, ACX_REG_INTERRUPT_CLEAR, pFwEvent->tFwStatusTxn.pFwStatus, REGISTER_SIZE, NULL, NULL) + /* FW status from memory area */ + pTxn = (TTxnStruct*)&pFwEvent->tMemFwStatusTxn.tTxnStruct; + TXN_PARAM_SET(pTxn, TXN_HIGH_PRIORITY, TXN_FUNC_ID_WLAN, TXN_DIRECTION_READ, TXN_INC_ADDR) + BUILD_TTxnStruct(pTxn, FW_STATUS_MEM_ADDRESS, pFwEvent->tMemFwStatusTxn.pFwStatus, sizeof(FwStatus_t)-REGISTER_SIZE, (TTxnDoneCb)fwEvent_ReadCompleteCb, hFwEvent) +#else + 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, ACX_REG_INTERRUPT_CLEAR, pFwEvent->tFwStatusTxn.pFwStatus, sizeof(FwStatus_t), (TTxnDoneCb)fwEvent_ReadCompleteCb, hFwEvent) +#endif + /* + * 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_Handle, + hFwEvent, + TI_FALSE, + "FW_EVENT", + sizeof("FW_EVENT")); + + return TI_OK; +} + + +/* + * \brief Call FwEvent client's event handler + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * + * \sa fwEvent_ReadCompleteCb + */ +static void fwEvent_CallHandler (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + if (pFwEvent->uEventVector & ACX_INTR_WATCHDOG) + { + /* Fw watchdog timeout has occured */ + TWD_WdExpireEvent (pFwEvent->hTWD); + } + + if (pFwEvent->uEventVector & ACX_INTR_INIT_COMPLETE) + { + TRACE0(pFwEvent->hReport, REPORT_SEVERITY_INFORMATION, "fwEvent_CallHandler: INIT_COMPLETE\n"); + } + /* Change to handle the command MBOX before the event MBOX to maintain order for WHA command response + * and follow command complete + */ + if (pFwEvent->uEventVector & ACX_INTR_CMD_COMPLETE) + { + /* Command Mbox completed */ + cmdMbox_CommandComplete(pFwEvent->hCmdMbox); + } + if (pFwEvent->uEventVector & ACX_INTR_EVENT_A) + { + eventMbox_Handle(pFwEvent->hEventMbox,(FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus)); + } + if (pFwEvent->uEventVector & ACX_INTR_EVENT_B) + { + eventMbox_Handle(pFwEvent->hEventMbox,(FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus)); + } + + + /* The DATA interrupt is shared by all data path events, so call all Tx and Rx clients */ + if (pFwEvent->uEventVector & ACX_INTR_DATA) + { + rxXfer_RxEvent (pFwEvent->hRxXfer, (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus)); + + txHwQueue_UpdateFreeResources (pFwEvent->hTxHwQueue, (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus)); + + txResult_TxCmpltIntrCb (pFwEvent->hTxResult, (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus)); + } + + /* After handling all raised bits, we can negate them */ + ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus &= pFwEvent->uEventMask; +} + + +/* + * \brief Requests the context engine to schedule the driver task + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * Called by the FW-Interrupt ISR. + * Requests the context engine to schedule the driver task + * for handling the FW-Events (FwEvent callback). + * + * \sa + */ +void fwEvent_InterruptRequest (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + /* Request switch to driver context for handling the FW-Interrupt event */ + context_RequestSchedule (pFwEvent->hContext, pFwEvent->uContextId); +} + + +/* + * \brief Handle the FW interrupts + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * Called from context module upon receiving FW interrupt + * The function mask the interrupts and reads the FW status + * + * \sa + */ + +void fwEvent_Handle (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + ETxnStatus rc; + + /* NOTE: pFwEvent may be uninitialized at init stage */ + if (pFwEvent != NULL) + { + if (pFwEvent->eFwEventState != FW_EVENT_STATE_IDLE) + { + os_InterruptServiced (pFwEvent->hOs); + twIf_HwAvailable(pFwEvent->hTwIf); + return; + } + + pFwEvent->eFwEventState = FW_EVENT_STATE_READING; + pFwEvent->bFwNotificationFlag = TI_TRUE; + + twIf_Awake(pFwEvent->hTwIf); + twIf_HwAvailable(pFwEvent->hTwIf); + + /* Write HINT mask */ + *((TI_UINT32*)(pFwEvent->tMaskTxn.pData)) = ACX_INTR_ALL; + TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent) + twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMaskTxn.tTxnStruct)); + +#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */ + /* + * Read first register (HINT_STT_CLR) only from registers area + */ + TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent) + twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct)); + + /* + * Read other 16 registers value from memory area FW_STATUS_MEM_ADDRESS + */ + TXN_FW_EVENT_SET_FW_MEM_ADDR(pFwEvent) + rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMemFwStatusTxn.tTxnStruct)); + + if (rc == TXN_STATUS_COMPLETE) + { + fwEvent_ReadCompleteCb(hFwEvent); + } +#else + + /* Read the Fw status */ + TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent) + rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct)); + + if (rc == TXN_STATUS_COMPLETE) + { + fwEvent_ReadCompleteCb(hFwEvent); + } +#endif + } + else + { + os_InterruptServiced (pFwEvent->hOs); + + /* end of if */ + } +} + + +/* + * \brief Handle the Fw Status information + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * This function is called from fwEvent_Handle on a sync read, or from TwIf as a CB on an async read. + * It calls fwEvent_CallHandler to handle the triggered interrupts. + * + * \sa fwEvent_Handle + */ +void fwEvent_ReadCompleteCb (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + +#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */ + /* + * copy FW status 16 registers values from memory transaction read area to the original place +*/ + os_memoryCopy (pFwEvent->hOs, &((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->counters, &((FwStatus_t*)(pFwEvent->tMemFwStatusTxn.pFwStatus))->counters, sizeof(FwStatus_t)-REGISTER_SIZE); +#endif + + os_InterruptServiced (pFwEvent->hOs); + + /* If we were called because of an interrupt */ + if (pFwEvent->bFwNotificationFlag) + { + /* In case of level interrupt we need to clear the line */ + /*os_InterruptServiced(pFwEvent->hOs);*/ + + /* + * Sync to fw time so we can update the tx packets + * on the delta time that they spent in the driver + */ + pFwEvent->uFwTimeOffset = (os_timeStampMs (pFwEvent->hOs) * 1000) - + ENDIAN_HANDLE_LONG (((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->fwLocalTime); + + pFwEvent->bFwNotificationFlag = TI_FALSE; + } + + pFwEvent->uEventVector = ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus; + + /* + * Mask unwanted interrupts. + */ + pFwEvent->uEventVector &= pFwEvent->uEventMask; + + fwEvent_CallHandler(hFwEvent); + + /* Check if the state is changed in the context of the event callbacks */ + if (pFwEvent->eFwEventState == FW_EVENT_STATE_IDLE) + { + /* + * When fwEvent_stop is called state is changed to IDLE + * This is done in the context of the above events callbacks + * Don't send the UNMASK transaction because the driver stop process includes power off + */ + TRACE0(pFwEvent->hReport, REPORT_SEVERITY_WARNING, "fwEvent_ReadCompleteCb : State is IDLE ! don't send the UNMASK"); + return; + } + + /* Write HINT unmask */ + *((TI_UINT32*)(pFwEvent->tUnMaskTxn.pData)) = ~pFwEvent->uEventMask; + TXN_FW_EVENT_SET_UNMASK_ADDR(pFwEvent) + twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tUnMaskTxn.tTxnStruct)); + + twIf_Sleep(pFwEvent->hTwIf); + pFwEvent->eFwEventState = FW_EVENT_STATE_IDLE; +} + + +/* + * \brief Translate host to FW time (Usec) + * + * \param hFwEvent - FwEvent Driver handle + * \param uHostTime - The host time in MS to translate + * + * \return FW Time in Usec + * + * \par Description + * + * \sa + */ +TI_UINT32 fwEvent_TranslateToFwTime (TI_HANDLE hFwEvent, TI_UINT32 uHostTime) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + return ((uHostTime * 1000) - pFwEvent->uFwTimeOffset); +} + + +/* + * \brief Unmask only cmd-cmplt and events interrupts (needed for init phase) + * + * \param hFwEvent - FwEvent Driver handle + * \return Event mask + * + * \par Description + * Unmask only cmd-cmplt and events interrupts (needed for init phase) + * and return interrupt enabled bit mask. + * + * \sa + */ +TI_UINT32 fwEvent_GetInitMask (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + /* Unmask only the interrupts needed for the FW configuration process. */ + pFwEvent->uEventMask = ACX_INTR_CMD_COMPLETE | ACX_INTR_EVENT_A | ACX_INTR_EVENT_B; + + return pFwEvent->uEventMask; +} + + +/* + * \brief Stop & reset FwEvent (called by the driver stop process) + * + * \param hFwEvent - FwEvent Driver handle + * \return TI_OK + * + * \par Description + * + * \sa + */ +TI_STATUS fwEvent_Stop (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + pFwEvent->eFwEventState = FW_EVENT_STATE_IDLE; + ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus = 0; + pFwEvent->uEventMask = 0; + pFwEvent->bFwNotificationFlag = TI_FALSE; + pFwEvent->uEventVector = 0; + + return TI_OK; +} + + +/* + * \brief Unmask all interrupts, set Rx interrupt bit and call FwEvent_Handle + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * Called when driver Start or recovery process is completed. + * Unmask all interrupts, set Rx interrupt bit and call FwEvent_Handle + * (in case we missed an Rx interrupt in a recovery process). + * + * \sa + */ +void fwEvent_EnableExternalEvents (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + /* Unmask all interrupts */ + pFwEvent->uEventMask = ALL_EVENTS_VECTOR; + + /* Set Rx interrupt bit to invoke it (in case we missed it in a recovery/start process) */ + ((FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus))->intrStatus |= ACX_INTR_DATA; + + /* If in IDLE state, handle interrupts including the Rx we've just set manually */ + if (pFwEvent->eFwEventState == FW_EVENT_STATE_IDLE) + { + fwEvent_GetFwStatus (hFwEvent); + } +} + + +/* + * \brief Disable the FwEvent client of the context thread handler + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * + * \sa + */ +void fwEvent_DisableInterrupts(TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + context_DisableClient (pFwEvent->hContext,pFwEvent->uContextId); + +} + + +/* + * \brief Enable the FwEvent client of the context thread handler + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * + * \sa + */ +void fwEvent_EnableInterrupts(TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + + context_EnableClient (pFwEvent->hContext,pFwEvent->uContextId); + +} + + +/* + * \brief Issue a FW status read (Not in response to any FW interrupt) + * + * \param hFwEvent - FwEvent Driver handle + * \return void + * + * \par Description + * Issue a FW status read (Not in response to any FW interrupt) + * Called also from fwEvent_EnableExternalEvents after recovery. + * + * \sa fwEvent_EnableExternalEvents + */ +void fwEvent_GetFwStatus (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + ETxnStatus rc; + + /* NOTE: pFwEvent may be uninitialized at init stage */ + if (pFwEvent != NULL) + { + if (pFwEvent->eFwEventState != FW_EVENT_STATE_IDLE) + { + twIf_HwAvailable(pFwEvent->hTwIf); + return; + } + + pFwEvent->eFwEventState = FW_EVENT_STATE_READING; + + twIf_Awake(pFwEvent->hTwIf); + + /* Write HINT mask */ + *((TI_UINT32*)(pFwEvent->tMaskTxn.pData)) = ACX_INTR_ALL; + TXN_FW_EVENT_SET_MASK_ADDR(pFwEvent) + twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMaskTxn.tTxnStruct)); + +#ifdef USE_SDIO_24M_WORKAROUND /* FW_STATUS moved from registers to memory area */ + /* + * Read first register (HINT_STT_CLR) only from registers area + */ + TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent) + twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct)); + + /* + * Read other 16 registers value from memory area 0x40200 + */ + TXN_FW_EVENT_SET_FW_MEM_ADDR(pFwEvent) + rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tMemFwStatusTxn.tTxnStruct)); + + if (rc == TXN_STATUS_COMPLETE) + { + fwEvent_ReadCompleteCb(hFwEvent); + } +#else + /* Read the Fw status */ + TXN_FW_EVENT_SET_STATUS_ADDR(pFwEvent) + rc = twIf_Transact(pFwEvent->hTwIf, &(pFwEvent->tFwStatusTxn.tTxnStruct)); + + if (rc == TXN_STATUS_COMPLETE) + { + fwEvent_ReadCompleteCb(hFwEvent); + } +#endif + /* end of if */ + } +} + + +#ifdef TI_DBG + +void fwEvent_PrintStat (TI_HANDLE hFwEvent) +{ + TfwEvent *pFwEvent = (TfwEvent *)hFwEvent; + FwStatus_t *fwStat = (FwStatus_t*)(pFwEvent->tFwStatusTxn.pFwStatus); + int i; + + WLAN_OS_REPORT(("Print FW event module info\n")); + WLAN_OS_REPORT(("==========================\n")); + WLAN_OS_REPORT(("intrStatus = 0x%08x\n", fwStat->intrStatus)); + WLAN_OS_REPORT(("counters = 0x%08x\n", fwStat->counters)); + for (i = 0; i < NUM_RX_PKT_DESC; i++) + { + WLAN_OS_REPORT(("rxPktsDesc[%1d] = 0x%08x\n", i, fwStat->rxPktsDesc[i])); + } + for (i = 0; i < NUM_TX_QUEUES; i++) + { + WLAN_OS_REPORT(("txReleasedBlks[%1d] = 0x%08x\n", i, fwStat->txReleasedBlks[i])); + } + WLAN_OS_REPORT(("fwLocalTime = 0x%08x\n", fwStat->fwLocalTime)); +} + +#endif /* TI_DBG */ +