/*
* healthMonitor.c
*
* Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved.
* All rights reserved.
*
* 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 healthMonitor.c
* \brief Firmware Recovery Mechanism
*/
/** \file healthMonitor.c
* \brief The health monitor module. Gets failures indications and handle them.
*
* For periodic check, use HW watchdog mechanizem instead of local periodic timer check
*
* \see healthMonitor.h
*/
#define __FILE_ID__ FILE_ID_66
#include "healthMonitor.h"
#include "osApi.h"
#include "timer.h"
#include "report.h"
#include "siteMgrApi.h"
#include "PowerMgr_API.h"
#include "currBss.h"
#include "DataCtrl_Api.h"
#include "TWDriver.h"
#include "SoftGeminiApi.h"
#include "currBss.h"
#include "rsnApi.h"
#include "DrvMain.h"
#include "DrvMainModules.h"
#include "TWDriverInternal.h"
typedef struct
{
/* handles to other modules */
TI_HANDLE hOs; /* handle to the OS object */
TI_HANDLE hReport; /* handle to the report object */
TI_HANDLE hTWD; /* handle to the TWD object */
TI_HANDLE hSiteMgr; /* handle to the site manager object */
TI_HANDLE hScr; /* handle to the SCR object */
TI_HANDLE hSoftGemini; /* handle to the Soft Gemini object */
TI_HANDLE hDrvMain; /* handle to the Recovery Mgr object */
TI_HANDLE hTxCtrl; /* handle to the TX Ctrl object */
TI_HANDLE hCurrBss; /* handle to the currBss object */
TI_HANDLE hRsn; /* handle to the RSN */
TI_HANDLE hTimer; /* handle to the Timer module object */
TI_HANDLE hContext; /* handle to the context-engine object */
/* Timers handles */
TI_HANDLE hFailTimer; /* failure event timer */
/* Management variables */
TI_UINT32 numOfHealthTests; /* number of health tests performed counter */
healthMonitorState_e state; /* health monitor state */
TI_BOOL bFullRecoveryEnable; /* full recovery enable flag */
TI_BOOL recoveryTriggerEnabled [MAX_FAILURE_EVENTS];
/* recovery enable flags per trigger type */
TI_UINT32 failureEvent; /* current recovery trigger */
TI_UINT32 keepAliveIntervals; /* number of health monitor timer intervals at which keep alive should be sent */
TI_UINT32 currentKeepAliveCounter;/* counting how many timer intervals had passed w/o a keep alive */
/* Recoveries Statistics */
TI_UINT32 recoveryTriggersNumber [MAX_FAILURE_EVENTS];
/* Number of times each recovery trigger occured */
TI_UINT32 numOfRecoveryPerformed; /* number of recoveries performed */
} THealthMonitor;
static void healthMonitor_proccessFailureEvent (TI_HANDLE hHealthMonitor, TI_BOOL bTwdInitOccured);
#ifdef REPORT_LOG
static char* sRecoveryTriggersNames [MAX_FAILURE_EVENTS] =
{
"NO_SCAN_COMPLETE_FAILURE",
"MBOX_FAILURE",
"HW_AWAKE_FAILURE",
"TX_STUCK",
"DISCONNECT_TIMEOUT",
"POWER_SAVE_FAILURE",
"MEASUREMENT_FAILURE",
"BUS_FAILURE",
"HW_WD_EXPIRE",
"RX_XFER_FAILURE"
};
#endif
/**
* \fn healthMonitor_create
* \brief Create module object
*
* Create module object.
*
* \note
* \param hOs - The OS adaptation handle
* \return The created module handle
* \sa
*/
TI_HANDLE healthMonitor_create (TI_HANDLE hOs)
{
THealthMonitor *pHealthMonitor;
/* Allocate memory for the health monitor object and nullify it */
pHealthMonitor = (THealthMonitor*)os_memoryAlloc (hOs, sizeof(THealthMonitor));
if (pHealthMonitor == NULL)
{
return NULL;
}
os_memoryZero (hOs, pHealthMonitor, sizeof(THealthMonitor));
/* Store OS object handle */
pHealthMonitor->hOs = hOs;
return (TI_HANDLE)pHealthMonitor;
}
/**
* \fn healthMonitor_init
* \brief Init module handles and variables
*
* Init module handles and variables.
*
* \note
* \param pStadHandles - The driver modules handles
* \return void
* \sa
*/
void healthMonitor_init (TStadHandlesList *pStadHandles)
{
THealthMonitor *pHealthMonitor = (THealthMonitor *)(pStadHandles->hHealthMonitor);
pHealthMonitor->hReport = pStadHandles->hReport;
pHealthMonitor->hTWD = pStadHandles->hTWD;
pHealthMonitor->hSiteMgr = pStadHandles->hSiteMgr;
pHealthMonitor->hScr = pStadHandles->hSCR;
pHealthMonitor->hSoftGemini = pStadHandles->hSoftGemini;
pHealthMonitor->hDrvMain = pStadHandles->hDrvMain;
pHealthMonitor->hTxCtrl = pStadHandles->hTxCtrl;
pHealthMonitor->hCurrBss = pStadHandles->hCurrBss;
pHealthMonitor->hRsn = pStadHandles->hRsn;
pHealthMonitor->hTimer = pStadHandles->hTimer;
pHealthMonitor->hContext = pStadHandles->hContext;
pHealthMonitor->state = HEALTH_MONITOR_STATE_DISCONNECTED;
pHealthMonitor->failureEvent = (TI_UINT32)NO_FAILURE;
/* Register the failure event callback */
TWD_RegisterCb (pHealthMonitor->hTWD,
TWD_EVENT_FAILURE,
(void *)healthMonitor_sendFailureEvent,
(void *)pHealthMonitor);
}
/**
* \fn healthMonitor_SetDefaults
* \brief Set module defaults and create timers
*
* Set module defaults from Ini-file and create timers.
*
* \note
* \param hHealthMonitor - The module's handle
* \param healthMonitorInitParams - The module's parameters default values (from Ini-file).
* \return void
* \sa
*/
TI_STATUS healthMonitor_SetDefaults (TI_HANDLE hHealthMonitor, healthMonitorInitParams_t *healthMonitorInitParams)
{
THealthMonitor *pHealthMonitor = hHealthMonitor;
int i;
/* Registry configuration */
pHealthMonitor->bFullRecoveryEnable = healthMonitorInitParams->FullRecoveryEnable;
for (i = 0; i < MAX_FAILURE_EVENTS; i++)
{
pHealthMonitor->recoveryTriggerEnabled[i] = healthMonitorInitParams->recoveryTriggerEnabled[i];
}
/* Create recovery request timer */
pHealthMonitor->hFailTimer = tmr_CreateTimer (pHealthMonitor->hTimer);
if (pHealthMonitor->hFailTimer == NULL)
{
TRACE0(pHealthMonitor->hReport, REPORT_SEVERITY_ERROR, "healthMonitor_SetDefaults(): Failed to create hFailTimer!\n");
return TI_NOK;
}
return TI_OK;
}
/***********************************************************************
* healthMonitor_unload
***********************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
RETURN:
************************************************************************/
TI_STATUS healthMonitor_unload (TI_HANDLE hHealthMonitor)
{
THealthMonitor *pHealthMonitor;
pHealthMonitor = (THealthMonitor*)hHealthMonitor;
if (pHealthMonitor != NULL)
{
if (NULL != pHealthMonitor->hFailTimer)
{
/* Release the timer */
tmr_DestroyTimer (pHealthMonitor->hFailTimer);
}
/* Freeing the object should be called last !!!!!!!!!!!! */
os_memoryFree (pHealthMonitor->hOs, pHealthMonitor, sizeof(THealthMonitor));
}
return TI_OK;
}
/***********************************************************************
* healthMonitor_setState
***********************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
RETURN:
************************************************************************/
void healthMonitor_setState (TI_HANDLE hHealthMonitor, healthMonitorState_e state)
{
THealthMonitor *pHealthMonitor = (THealthMonitor*)hHealthMonitor;
pHealthMonitor->state = state;
}
/***********************************************************************
* healthMonitor_PerformTest
***********************************************************************
DESCRIPTION: Called periodically by timer every few seconds (depends on connection state),
or optionally by external application.
INPUT: hHealthMonitor - Module handle.
bTwdInitOccured - Indicates if TWDriver recovery occured since timer started
OUTPUT:
RETURN:
************************************************************************/
void healthMonitor_PerformTest (TI_HANDLE hHealthMonitor, TI_BOOL bTwdInitOccured)
{
THealthMonitor *pHealthMonitor = (THealthMonitor*)hHealthMonitor;
pHealthMonitor->numOfHealthTests++;
/* Send health-check command to FW, just to ensure command complete is accepted */
TWD_CmdHealthCheck (pHealthMonitor->hTWD);
}
/***********************************************************************
* healthMonitor_sendFailureEvent
***********************************************************************
DESCRIPTION: Entry point for all low level modules to send a failure evrnt
INPUT: handle - health monitor handle
failureEvent - the error
OUTPUT:
RETURN:
************************************************************************/
void healthMonitor_sendFailureEvent (TI_HANDLE hHealthMonitor, EFailureEvent failureEvent)
{
THealthMonitor *pHealthMonitor = (THealthMonitor*)hHealthMonitor;
/* Check the recovery process is already running */
if (pHealthMonitor->failureEvent < MAX_FAILURE_EVENTS)
{
TRACE0(pHealthMonitor->hReport, REPORT_SEVERITY_WARNING , ": recovery process is already handling , new trigger is \n");
}
/* Recovery is performed only if this trigger is enabled in the .INI file */
else if (pHealthMonitor->recoveryTriggerEnabled[failureEvent])
{
pHealthMonitor->failureEvent = failureEvent;
/*
* NOTE: start timer with minimum expiry (1 msec) for recovery will start
* from the top of the stack
*/
tmr_StartTimer (pHealthMonitor->hFailTimer,
healthMonitor_proccessFailureEvent,
(TI_HANDLE)pHealthMonitor,
1,
TI_FALSE);
}
else
{
TRACE0(pHealthMonitor->hReport, REPORT_SEVERITY_ERROR , ": Recovery trigger is disabled!\n");
}
}
/***********************************************************************
* healthMonitor_proccessFailureEvent
***********************************************************************
DESCRIPTION: this is the central error function - will be passed as call back
to the TnetWDriver modules. it will parse the error and dispatch the
relevant action (recovery or not)
INPUT: hHealthMonitor - health monitor handle
bTwdInitOccured - Indicates if TWDriver recovery occured since timer started
OUTPUT:
RETURN:
************************************************************************/
void healthMonitor_proccessFailureEvent (TI_HANDLE hHealthMonitor, TI_BOOL bTwdInitOccured)
{
THealthMonitor *pHealthMonitor = (THealthMonitor*)hHealthMonitor;
/* Check failure event validity */
if (pHealthMonitor->failureEvent < MAX_FAILURE_EVENTS)
{
pHealthMonitor->recoveryTriggersNumber[pHealthMonitor->failureEvent] ++;
TRACE2(pHealthMonitor->hReport, REPORT_SEVERITY_CONSOLE, "***** recovery trigger: failureEvent =%d *****, ts=%d\n", pHealthMonitor->failureEvent, os_timeStampMs(pHealthMonitor->hOs));
WLAN_OS_REPORT (("***** recovery trigger: %s *****, ts=%d\n", sRecoveryTriggersNames[pHealthMonitor->failureEvent], os_timeStampMs(pHealthMonitor->hOs)));
if (TWD_RecoveryEnabled (pHealthMonitor->hTWD))
{
pHealthMonitor->numOfRecoveryPerformed ++;
drvMain_Recovery (pHealthMonitor->hDrvMain);
}
else
{
TRACE0(pHealthMonitor->hReport, REPORT_SEVERITY_CONSOLE, "healthMonitor_proccessFailureEvent: Recovery is disabled in tiwlan.ini, abort recovery process\n");
WLAN_OS_REPORT(("healthMonitor_proccessFailureEvent: Recovery is disabled in tiwlan.ini, abort recovery process\n"));
}
pHealthMonitor->failureEvent = (TI_UINT32)NO_FAILURE;
}
else
{
TRACE1(pHealthMonitor->hReport, REPORT_SEVERITY_ERROR , "unsupported failure event = %d\n", pHealthMonitor->failureEvent);
}
}
/***********************************************************************
* healthMonitor_printFailureEvents
***********************************************************************
DESCRIPTION:
INPUT:
OUTPUT:
RETURN:
************************************************************************/
void healthMonitor_printFailureEvents(TI_HANDLE hHealthMonitor)
{
#ifdef TI_DBG
#ifdef REPORT_LOG
THealthMonitor *pHealthMonitor = (THealthMonitor*)hHealthMonitor;
int i;
WLAN_OS_REPORT(("-------------- STA Health Failure Statistics ---------------\n"));
WLAN_OS_REPORT(("FULL RECOVERY PERFORMED = %d\n", pHealthMonitor->numOfRecoveryPerformed));
for (i = 0; i < MAX_FAILURE_EVENTS; i++)
{
WLAN_OS_REPORT(("%27s= %d\n", sRecoveryTriggersNames[ i ], pHealthMonitor->recoveryTriggersNumber[ i ]));
}
WLAN_OS_REPORT(("Maximum number of commands in mailbox queue = %u\n", TWD_GetMaxNumberOfCommandsInQueue(pHealthMonitor->hTWD)));
WLAN_OS_REPORT(("Health Test Performed = %d\n", pHealthMonitor->numOfHealthTests));
WLAN_OS_REPORT(("\n"));
#endif
#endif /* TI_DBG */
}
/***********************************************************************
* healthMonitor_SetParam
***********************************************************************
DESCRIPTION: Set module parameters from the external command interface
INPUT: hHealthMonitor - module handle.
pParam - Pointer to the parameter
OUTPUT:
RETURN: TI_OK on success, TI_NOK otherwise
************************************************************************/
TI_STATUS healthMonitor_SetParam (TI_HANDLE hHealthMonitor, paramInfo_t *pParam)
{
THealthMonitor *pHealthMonitor = (THealthMonitor*)hHealthMonitor;
TI_STATUS eStatus = TI_OK;
TRACE1(pHealthMonitor->hReport, REPORT_SEVERITY_INFORMATION, "healthMonitor_SetParam() - %d\n", pParam->paramType);
switch(pParam->paramType)
{
case HEALTH_MONITOR_CHECK_DEVICE:
/* Send health check command to FW if we are not disconnceted */
if (pHealthMonitor->state != HEALTH_MONITOR_STATE_DISCONNECTED)
{
healthMonitor_PerformTest (hHealthMonitor, TI_FALSE);
}
break;
default:
TRACE1(pHealthMonitor->hReport, REPORT_SEVERITY_ERROR, "healthMonitor_SetParam(): Params is not supported, %d\n", pParam->paramType);
}
return eStatus;
}
/***********************************************************************
* healthMonitor_GetParam
***********************************************************************
DESCRIPTION: Get module parameters from the external command interface
INPUT: hHealthMonitor - module handle.
pParam - Pointer to the parameter
OUTPUT:
RETURN: TI_OK on success, TI_NOK otherwise
************************************************************************/
TI_STATUS healthMonitor_GetParam (TI_HANDLE hHealthMonitor, paramInfo_t *pParam)
{
return TI_OK;
}