/**************************************************************** **************************************************************** ** ** ** (C)Copyright 2005-2006, American Megatrends Inc. ** ** ** ** All Rights Reserved. ** ** ** ** 6145-F, Northbelt Parkway, Norcross, ** ** ** ** Georgia - 30071, USA. Phone-(770)-246-8600. ** ** ** **************************************************************** ****************************************************************/ /***************************************************************** * * WDT.c * WadtchDog TimeOut function * * Author: Govind Kothandapani * : Rama Bisa * : Basavaraj Astekar * : Bakka Ravinder Reddy * *****************************************************************/ #define ENABLE_DEBUG_MACROS 0 #include "Types.h" #include "WDT.h" #include "Message.h" #include "Debug.h" #include "WDT.h" #include "IPMIDefs.h" #include "NVRAccess.h" #include "IPMI_Sensor.h" #include "Events.h" #include "Platform.h" #include "SharedMem.h" #include "ChassisDevice.h" #include "ChassisAPI.h" #include"IPMI_KCS.h" #include "ChassisCtrl.h" #include "PDKAccess.h" #include "IPMIConf.h" #include "Util.h" #include "LANConfig.h" #include #include "featuredef.h" #include "featuredef.h" #include "flashlib.h" /*** Local macro definitions ***/ #define PRE_TIMEOUT 1 #define WDT_TIMEOUT 2 #define PRETIMEOUT_ACTION_TAKEN 0x08 #define TIMEOUT_NO_ACTION_TAKEN 0x00 #define TIMEOUT_ACTION_HARD_RESET 0x01 #define TIMEOUT_ACTION_POWER_DOWN 0x02 #define TIMEOUT_ACTION_POWER_CYCLE 0x03 #define PRE_TIMEOUT_SMI 0x10 #define PRE_TIMEOUT_NMI_DIAG 0x20 #define PRE_TIMEOUT_MESSAGING_INTR 0x30 /*** Global variables **/ _FAR_ WDTTmrMgr_T g_WDTTmrMgr; /*---------------------------------------------------------------- * WatchDog2 Event Offsets *---------------------------------------------------------------*/ #define IPMI_WDT_TIMER_EXPIRED 0x00 //Watch Dog Expired Status only offset #define IPMI_WDT_HARD_RESET 0x01 #define IPMI_WDT_POWER_DOWN 0x02 #define IPMI_WDT_POWER_CYCLE 0x03 #define IPMI_WDT_TIMER_INTERRUPT 0x08 #define MAX_WDT_MS_VALUE(Hertz) (0xFFFFFFFF * 1000)/Hertz /*** Function Prototypes ***/ static void WDTTmrAction (INT8U TmrAction, int BMCInst); /* Declare Thread Mutex */ //OS_THREAD_MUTEX_DECLARE(hWDTSharedMemMutex); /** * WDTTimerTask **/ void * WDTTimerTask (void *pArg) { int *inst = (int*) pArg; int BMCInst = *inst; _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst]; INT32U WDTInterval = 0,WDTPreInterval = 0,jiffycmp = 0; long long jiffyvalue=0,jiffystart = 0; unsigned long Hertz = sysconf(_SC_CLK_TCK); prctl(PR_SET_NAME,__FUNCTION__,0,0,0); /* Get the Shared memory mutex handle */ OS_THREAD_MUTEX_INIT(pBMCInfo->hWDTSharedMemMutex, PTHREAD_MUTEX_RECURSIVE); while(TRUE) { /* Will be waiting till the Watchdog timer is armed*/ sem_wait(&pBMCInfo->WDTSem); /* If no timer to process return */ if (FALSE == BMC_GET_SHARED_MEM(BMCInst)->IsWDTPresent) { continue; } WDTInterval = pBMCInfo->WDTConfig.InitCountDown * WDT_COUNT_MS; if ((pBMCInfo->WDTConfig.TmrActions & 0x70) == 0) { WDTPreInterval = WDTInterval+1; } else { WDTPreInterval = 1000 * pBMCInfo->WDTConfig.PreTimeOutInterval; } if(GetJiffySysCtlvalue(JIFFY_VALUE,&jiffyvalue) == 1) { IPMI_ERROR("Error in getting Jiffy value \n"); return 0; } jiffystart = jiffyvalue; while(1) { if(GetJiffySysCtlvalue(JIFFY_VALUE,&jiffyvalue) == 1) { IPMI_ERROR("Error in getting Jiffy value \n"); return 0; } if (pBMCInfo->HostOFFStopWDT == TRUE) { pBMCInfo->HostOFFStopWDT = FALSE; break; } if(pBMCInfo->SetWDTUpdated == TRUE && (TRUE == BMC_GET_SHARED_MEM(BMCInst)->IsWDTPresent)) { jiffystart = jiffyvalue; WDTInterval = pBMCInfo->WDTConfig.InitCountDown * WDT_COUNT_MS; if ((pBMCInfo->WDTConfig.TmrActions & 0x70) == 0) { WDTPreInterval = WDTInterval+1; } else { WDTPreInterval = 1000 * pBMCInfo->WDTConfig.PreTimeOutInterval; } pBMCInfo->SetWDTUpdated = FALSE; } else if(pBMCInfo->SetWDTUpdated == TRUE && (FALSE== BMC_GET_SHARED_MEM(BMCInst)->IsWDTPresent)) { /* Restore Initial countdown value */ g_WDTTmrMgr.TmrInterval = pBMCInfo->WDTConfig.InitCountDown; break; } if(jiffyvalue < jiffystart) { /* To handle Jiffy Overflow condition */ jiffycmp = (MAX_WDT_MS_VALUE(Hertz) -jiffystart) + jiffyvalue; } else { jiffycmp = jiffyvalue - jiffystart; } if((jiffycmp > WDTInterval) ||(jiffycmp > (WDTInterval-WDTPreInterval))) { if((jiffycmp > (WDTInterval-WDTPreInterval)) && (pBMCInfo->WDTPreTmtStat == FALSE) && ((pBMCInfo->WDTConfig.TmrActions & 0x70) != 0)) { /* take pretimeout actions */ if(pBMCInfo->TriggerEvent.WDTTimeExpire) { if(0 == send_signal_by_name("Adviserd",SIGUSR2)) { TDBG("Signal Sent successfully to adviser to start recording video\n"); } else { TDBG("Cannot Send Signal to adviser to start recording video\n"); } } WDTTmrAction (g_WDTTmrMgr.WDTTmr.TmrActions & 0x70, BMCInst); pBMCInfo->WDTPreTmtStat = TRUE; } else if(jiffycmp > WDTInterval) { g_WDTTmrMgr.TmrPresent = FALSE; OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->hWDTSharedMemMutex, WAIT_INFINITE) BMC_GET_SHARED_MEM(BMCInst)->IsWDTRunning=FALSE; BMC_GET_SHARED_MEM(BMCInst)->IsWDTPresent =FALSE; // Modify ARP status to resume the thread // after receiving set Watchdog Timer command //BMC_GET_SHARED_MEM(BMCInst)->GratArpStatus = RESUME_ARPS; INT8U i = 0; for (i = 0; i < MAX_LAN_CHANNELS; i++) { if((pBMCInfo->LanIfcConfig[i].Enabled == TRUE) && (pBMCInfo->LanIfcConfig[i].Up_Status == LAN_IFC_UP)) { BMC_GET_SHARED_MEM(BMCInst)->ArpSuspendStatus[i] = RESUME_ARPS; UpdateArpStatus(pBMCInfo->LanIfcConfig[i].Ethindex, BMC_GET_SHARED_MEM(BMCInst)->IsWDTRunning, BMCInst); } } OS_THREAD_MUTEX_RELEASE(&pBMCInfo->hWDTSharedMemMutex); /* Take WDT timeout Actions */ pBMCInfo->WDTPreTmtStat = FALSE; g_WDTTmrMgr.TmrInterval = 0; if(pBMCInfo->TriggerEvent.WDTTimeExpire) { if(0 == send_signal_by_name("Adviserd",SIGUSR2)) { TDBG("Signal Sent successfully to adviser to start recording video\n"); } else { TDBG("Cannot Send Signal to adviser to start recording video\n"); } } WDTTmrAction (g_WDTTmrMgr.WDTTmr.TmrActions & 0x07, BMCInst); break; } } if((jiffycmp -WDTInterval) > 20) { /* Made to sleep for 100ms to reduce CPU Usage */ usleep(WDT_SLEEP_TIME); g_WDTTmrMgr.TmrInterval = pBMCInfo->WDTConfig.InitCountDown - (jiffycmp/WDT_COUNT_MS); } } } } /** * @brief Takes action depending on the argument. * @param TmrAction Timeout action. **/ static void WDTTmrAction (INT8U TmrAction, int BMCInst) { int i = 0; INT8U u8EventOffset; INT8U readFlags = 0; _FAR_ BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst]; _FAR_ SensorInfo_T* pSensorInfo; SensorSharedMem_T* pSMSharedMem; if(IsCardInFlashMode()){ return; } if (TmrAction & 0x70) { pBMCInfo->WDTConfig.PreTimeoutActionTaken = g_WDTTmrMgr.WDTTmr.PreTimeoutActionTaken = PRETIMEOUT_ACTION_TAKEN; if (pBMCInfo->IpmiConfig.KCS1IfcSupport == 1) { SET_SMS_ATN (0, BMCInst); if(g_corefeatures.kcs_obf_bit == ENABLED) { SET_OBF (0, BMCInst); } } if (pBMCInfo->IpmiConfig.KCS2IfcSupport == 1) { SET_SMS_ATN (1, BMCInst); if(g_corefeatures.kcs_obf_bit == ENABLED) { SET_OBF (1, BMCInst); } } if (pBMCInfo->IpmiConfig.KCS3IfcSuppport == 1) { SET_SMS_ATN (2, BMCInst); if(g_corefeatures.kcs_obf_bit == ENABLED) { SET_OBF (2, BMCInst); } } } else { pBMCInfo->WDTConfig.ExpirationFlag |= 0x1 << (pBMCInfo->WDTConfig.TmrUse & 0x07); // Based on the IPMI spec 27.7, the WDT expiration flag should not be preserved on any AC cycle. // update the WDT expiration flag in the global memory pool, not persistant in the flash g_WDTTmrMgr.WDTTmr.ExpirationFlag |= 0x1 << (pBMCInfo->WDTConfig.TmrUse & 0x07); } // setup sensor event offset u8EventOffset = TmrAction; if(g_corefeatures.wdt_flush_support == ENABLED ) { FlushIPMI((INT8U*)&pBMCInfo->WDTConfig,(INT8U*)&pBMCInfo->WDTConfig,pBMCInfo->IPMIConfLoc.WDTDATAddr, sizeof(WDTConfig_T),BMCInst); } if(g_PDKHandle[PDK_BEFOREWATCHDOGACTION] != NULL) { if( (((int(*)(INT8U,WDTTmrMgr_T*,int))g_PDKHandle[PDK_BEFOREWATCHDOGACTION]) (TmrAction, &g_WDTTmrMgr,BMCInst)) != 0) { return; } } else { if (g_PDKHandle[PDK_PREWATCHDOGACTION] != NULL) { if( (((int(*)(INT8U*, WDTTmrMgr_T*, int))g_PDKHandle[PDK_PREWATCHDOGACTION]) (&TmrAction, &g_WDTTmrMgr,BMCInst)) != 0) { return; } } } switch (TmrAction) { case TIMEOUT_NO_ACTION_TAKEN: break; case TIMEOUT_ACTION_HARD_RESET: //Added for GetSystem RestartCause // pBMCInfo->ChassisConfig.SysRestartCause = RESTART_CAUSE_WDT_EXPIRATION; //API_OnSetRestartCause(RESTART_CAUSE_WDT_EXPIRATION, TRUE); OnSetRestartCause(pBMCInfo->ChassisConfig.SysRestartCause, TRUE,BMCInst); // perform the chassis control action Platform_HostColdReset (BMCInst); break; case TIMEOUT_ACTION_POWER_DOWN: //Added for GetSystem RestartCause // pBMCInfo->ChassisConfig.SysRestartCause = RESTART_CAUSE_WDT_EXPIRATION; //API_OnSetRestartCause(RESTART_CAUSE_WDT_EXPIRATION, TRUE); OnSetRestartCause(pBMCInfo->ChassisConfig.SysRestartCause, TRUE,BMCInst); // perform the chassis control action Platform_HostPowerOff (BMCInst); break; case TIMEOUT_ACTION_POWER_CYCLE: //Added for GetSystem RestartCause // pBMCInfo->ChassisConfig.SysRestartCause = RESTART_CAUSE_WDT_EXPIRATION; //API_OnSetRestartCause(RESTART_CAUSE_WDT_EXPIRATION, TRUE); OnSetRestartCause(pBMCInfo->ChassisConfig.SysRestartCause, TRUE,BMCInst); // perform the chassis control action Platform_HostPowerCycle (BMCInst); break; case PRE_TIMEOUT_NMI_DIAG: // perform the NMI Platform_HostDiagInt (BMCInst); // fall through case PRE_TIMEOUT_SMI: case PRE_TIMEOUT_MESSAGING_INTR: // setup sensor event offset to be the timer interrupt (08h) u8EventOffset = IPMI_WDT_TIMER_INTERRUPT; break; default: IPMI_ERROR("Invalid Timer Action for watchdog.\n"); break; } // save the system restart cause even if there is no change FlushIPMI((INT8U*)&pBMCInfo->ChassisConfig,(INT8U*)&pBMCInfo->ChassisConfig,pBMCInfo->IPMIConfLoc.ChassisConfigAddr,sizeof(ChassisConfig_T),BMCInst); // pass the WDT event offset if(g_corefeatures.internal_sensor == ENABLED) { SetWD2SensorReading((1 << u8EventOffset), g_WDTTmrMgr.WDTTmr.TmrUse,g_WDTTmrMgr.WDTTmr.TmrActions,BMCInst); /* Get the Sensor Shared Memory */ pSMSharedMem = (_FAR_ SensorSharedMem_T*)&pBMCInfo->SensorSharedMem; for (i = 0; i < pBMCInfo->SenConfig.ValidSensorCnt; i++) { /* When the SensorType is WatchDog, calling WD2EventLog here to create EventLog instead through SensorMonitor */ if(pSMSharedMem->SensorInfo[pBMCInfo->SenConfig.ValidSensorList [i]].SensorTypeCode == SENSOR_TYPE_WATCHDOG2) { pSensorInfo = (SensorInfo_T*)&pSMSharedMem->SensorInfo[pBMCInfo->SenConfig.ValidSensorList [i]]; WD2EventLog(pSensorInfo,&readFlags,BMCInst); } } } if(g_PDKHandle[PDK_WATCHDOGACTION] != NULL) { ((void(*)(INT8U,WDTTmrMgr_T*,int))g_PDKHandle[PDK_WATCHDOGACTION]) (TmrAction,&g_WDTTmrMgr,BMCInst); } /* Clearing don't log bit after Watchdog timeout */ g_WDTTmrMgr.WDTTmr.TmrUse &= 0x7F; } /*----------------------------------------------------------------- * @fn StopWDTTimer * * @brief This is provided to stop Watchdog Timer. * * @return None. *-----------------------------------------------------------------*/ void StopWDTTimer (int BMCInst) { BMCInfo_t* pBMCInfo = &g_BMCInfo[BMCInst]; g_WDTTmrMgr.TmrPresent = FALSE; OS_THREAD_MUTEX_ACQUIRE(&pBMCInfo->hWDTSharedMemMutex, WAIT_INFINITE); BMC_GET_SHARED_MEM(BMCInst)->IsWDTRunning = FALSE; BMC_GET_SHARED_MEM(BMCInst)->IsWDTPresent = FALSE; OS_THREAD_MUTEX_RELEASE(&pBMCInfo->hWDTSharedMemMutex); }