#define TIME_UNITS_PER_SECOND 10000000\r
\r
// Tick frequency of the generic timer basis of the generic watchdog.\r
-UINTN mTimerFrequencyHz = 0;\r
+STATIC UINTN mTimerFrequencyHz = 0;\r
\r
/* In cases where the compare register was set manually, information about\r
how long the watchdog was asked to wait cannot be retrieved from hardware.\r
It is therefore stored here. 0 means the timer is not running. */\r
-UINT64 mNumTimerTicks = 0;\r
+STATIC UINT64 mNumTimerTicks = 0;\r
\r
-EFI_HARDWARE_INTERRUPT2_PROTOCOL *mInterruptProtocol;\r
+STATIC EFI_HARDWARE_INTERRUPT2_PROTOCOL *mInterruptProtocol;\r
+STATIC EFI_WATCHDOG_TIMER_NOTIFY mWatchdogNotify;\r
\r
+STATIC\r
VOID\r
WatchdogWriteOffsetRegister (\r
UINT32 Value\r
MmioWrite32 (GENERIC_WDOG_OFFSET_REG, Value);\r
}\r
\r
+STATIC\r
VOID\r
WatchdogWriteCompareRegister (\r
UINT64 Value\r
MmioWrite32 (GENERIC_WDOG_COMPARE_VALUE_REG_HIGH, (Value >> 32) & MAX_UINT32);\r
}\r
\r
+STATIC\r
VOID\r
WatchdogEnable (\r
VOID\r
MmioWrite32 (GENERIC_WDOG_CONTROL_STATUS_REG, GENERIC_WDOG_ENABLED);\r
}\r
\r
+STATIC\r
VOID\r
WatchdogDisable (\r
VOID\r
/** On exiting boot services we must make sure the Watchdog Timer\r
is stopped.\r
**/\r
+STATIC\r
VOID\r
EFIAPI\r
WatchdogExitBootServicesEvent (\r
/* This function is called when the watchdog's first signal (WS0) goes high.\r
It uses the ResetSystem Runtime Service to reset the board.\r
*/\r
+STATIC\r
VOID\r
EFIAPI\r
WatchdogInterruptHandler (\r
)\r
{\r
STATIC CONST CHAR16 ResetString[]= L"The generic watchdog timer ran out.";\r
+ UINT64 TimerPeriod;\r
\r
WatchdogDisable ();\r
\r
mInterruptProtocol->EndOfInterrupt (mInterruptProtocol, Source);\r
\r
- gRT->ResetSystem (\r
- EfiResetCold,\r
- EFI_TIMEOUT,\r
- StrSize (ResetString),\r
- (VOID *) &ResetString\r
- );\r
+ //\r
+ // The notify function should be called with the elapsed number of ticks\r
+ // since the watchdog was armed, which should exceed the timer period.\r
+ // We don't actually know the elapsed number of ticks, so let's return\r
+ // the timer period plus 1.\r
+ //\r
+ if (mWatchdogNotify != NULL) {\r
+ TimerPeriod = ((TIME_UNITS_PER_SECOND / mTimerFrequencyHz) * mNumTimerTicks);\r
+ mWatchdogNotify (TimerPeriod + 1);\r
+ }\r
+\r
+ gRT->ResetSystem (EfiResetCold, EFI_TIMEOUT, StrSize (ResetString),\r
+ (CHAR16 *)ResetString);\r
\r
// If we got here then the reset didn't work\r
ASSERT (FALSE);\r
@retval EFI_UNSUPPORTED The code does not support NotifyFunction.\r
\r
**/\r
+STATIC\r
EFI_STATUS\r
EFIAPI\r
WatchdogRegisterHandler (\r
- IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,\r
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,\r
IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction\r
)\r
{\r
- // ERROR: This function is not supported.\r
- // The watchdog will reset the board\r
- return EFI_UNSUPPORTED;\r
+ if (mWatchdogNotify == NULL && NotifyFunction == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (mWatchdogNotify != NULL && NotifyFunction != NULL) {\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ mWatchdogNotify = NotifyFunction;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
in TimerPeriod 100ns units.\r
\r
**/\r
+STATIC\r
EFI_STATUS\r
EFIAPI\r
WatchdogSetTimerPeriod (\r
- IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,\r
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,\r
IN UINT64 TimerPeriod // In 100ns units\r
)\r
{\r
@retval EFI_INVALID_PARAMETER TimerPeriod is NULL.\r
\r
**/\r
+STATIC\r
EFI_STATUS\r
EFIAPI\r
WatchdogGetTimerPeriod (\r
- IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,\r
+ IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,\r
OUT UINT64 *TimerPeriod\r
)\r
{\r
Retrieves the period of the timer interrupt in 100ns units.\r
\r
**/\r
-EFI_WATCHDOG_TIMER_ARCH_PROTOCOL gWatchdogTimer = {\r
- (EFI_WATCHDOG_TIMER_REGISTER_HANDLER)WatchdogRegisterHandler,\r
- (EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD)WatchdogSetTimerPeriod,\r
- (EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD)WatchdogGetTimerPeriod\r
+STATIC EFI_WATCHDOG_TIMER_ARCH_PROTOCOL mWatchdogTimer = {\r
+ WatchdogRegisterHandler,\r
+ WatchdogSetTimerPeriod,\r
+ WatchdogGetTimerPeriod\r
};\r
\r
-EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;\r
+STATIC EFI_EVENT mEfiExitBootServicesEvent;\r
\r
EFI_STATUS\r
EFIAPI\r
EFI_STATUS Status;\r
EFI_HANDLE Handle;\r
\r
+ Status = gBS->LocateProtocol (&gHardwareInterrupt2ProtocolGuid, NULL,\r
+ (VOID **)&mInterruptProtocol);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
/* Make sure the Watchdog Timer Architectural Protocol has not been installed\r
in the system yet.\r
This will avoid conflicts with the universal watchdog */\r
mTimerFrequencyHz = ArmGenericTimerGetTimerFreq ();\r
ASSERT (mTimerFrequencyHz != 0);\r
\r
- // Register for an ExitBootServicesEvent\r
- Status = gBS->CreateEvent (\r
- EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
- TPL_NOTIFY,\r
- WatchdogExitBootServicesEvent,\r
- NULL,\r
- &EfiExitBootServicesEvent\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- // Install interrupt handler\r
- Status = gBS->LocateProtocol (\r
- &gHardwareInterrupt2ProtocolGuid,\r
- NULL,\r
- (VOID **)&mInterruptProtocol\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Status = mInterruptProtocol->RegisterInterruptSource (\r
- mInterruptProtocol,\r
- FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum),\r
- WatchdogInterruptHandler\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Status = mInterruptProtocol->SetTriggerType (\r
- mInterruptProtocol,\r
- FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum),\r
- EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- // Install the Timer Architectural Protocol onto a new handle\r
- Handle = NULL;\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- &Handle,\r
- &gEfiWatchdogTimerArchProtocolGuid,\r
- &gWatchdogTimer,\r
- NULL\r
- );\r
- }\r
- }\r
- }\r
+ // Install interrupt handler\r
+ Status = mInterruptProtocol->RegisterInterruptSource (mInterruptProtocol,\r
+ FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum),\r
+ WatchdogInterruptHandler);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
+ Status = mInterruptProtocol->SetTriggerType (mInterruptProtocol,\r
+ FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum),\r
+ EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING);\r
+ if (EFI_ERROR (Status)) {\r
+ goto UnregisterHandler;\r
+ }\r
+\r
+ // Install the Timer Architectural Protocol onto a new handle\r
+ Handle = NULL;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (&Handle,\r
+ &gEfiWatchdogTimerArchProtocolGuid, &mWatchdogTimer,\r
+ NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ goto UnregisterHandler;\r
+ }\r
+\r
+ // Register for an ExitBootServicesEvent\r
+ Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY,\r
+ WatchdogExitBootServicesEvent, NULL,\r
+ &mEfiExitBootServicesEvent);\r
ASSERT_EFI_ERROR (Status);\r
\r
mNumTimerTicks = 0;\r
WatchdogDisable ();\r
\r
+ return EFI_SUCCESS;\r
+\r
+UnregisterHandler:\r
+ // Unregister the handler\r
+ mInterruptProtocol->RegisterInterruptSource (mInterruptProtocol,\r
+ FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum),\r
+ NULL);\r
return Status;\r
}\r