X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=ArmPkg%2FDrivers%2FGenericWatchdogDxe%2FGenericWatchdogDxe.c;h=a1ef0363eb399cbfd2221e5c8025c009c630b973;hp=8ccf15366dfadbfc9199cbec729934f0d9bd855d;hb=ba808d11f6a3206cbf4bee8340c7a26b2b19e809;hpb=dd4cae4d82c7477273f3da455084844db5cca0c0 diff --git a/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c b/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c index 8ccf15366d..a1ef0363eb 100644 --- a/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c +++ b/ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.c @@ -34,15 +34,17 @@ #define TIME_UNITS_PER_SECOND 10000000 // Tick frequency of the generic timer basis of the generic watchdog. -UINTN mTimerFrequencyHz = 0; +STATIC UINTN mTimerFrequencyHz = 0; /* In cases where the compare register was set manually, information about how long the watchdog was asked to wait cannot be retrieved from hardware. It is therefore stored here. 0 means the timer is not running. */ -UINT64 mNumTimerTicks = 0; +STATIC UINT64 mNumTimerTicks = 0; -EFI_HARDWARE_INTERRUPT2_PROTOCOL *mInterruptProtocol; +STATIC EFI_HARDWARE_INTERRUPT2_PROTOCOL *mInterruptProtocol; +STATIC EFI_WATCHDOG_TIMER_NOTIFY mWatchdogNotify; +STATIC VOID WatchdogWriteOffsetRegister ( UINT32 Value @@ -51,6 +53,7 @@ WatchdogWriteOffsetRegister ( MmioWrite32 (GENERIC_WDOG_OFFSET_REG, Value); } +STATIC VOID WatchdogWriteCompareRegister ( UINT64 Value @@ -60,6 +63,7 @@ WatchdogWriteCompareRegister ( MmioWrite32 (GENERIC_WDOG_COMPARE_VALUE_REG_HIGH, (Value >> 32) & MAX_UINT32); } +STATIC VOID WatchdogEnable ( VOID @@ -68,6 +72,7 @@ WatchdogEnable ( MmioWrite32 (GENERIC_WDOG_CONTROL_STATUS_REG, GENERIC_WDOG_ENABLED); } +STATIC VOID WatchdogDisable ( VOID @@ -79,6 +84,7 @@ WatchdogDisable ( /** On exiting boot services we must make sure the Watchdog Timer is stopped. **/ +STATIC VOID EFIAPI WatchdogExitBootServicesEvent ( @@ -93,6 +99,7 @@ WatchdogExitBootServicesEvent ( /* This function is called when the watchdog's first signal (WS0) goes high. It uses the ResetSystem Runtime Service to reset the board. */ +STATIC VOID EFIAPI WatchdogInterruptHandler ( @@ -101,17 +108,25 @@ WatchdogInterruptHandler ( ) { STATIC CONST CHAR16 ResetString[]= L"The generic watchdog timer ran out."; + UINT64 TimerPeriod; WatchdogDisable (); mInterruptProtocol->EndOfInterrupt (mInterruptProtocol, Source); - gRT->ResetSystem ( - EfiResetCold, - EFI_TIMEOUT, - StrSize (ResetString), - (VOID *) &ResetString - ); + // + // The notify function should be called with the elapsed number of ticks + // since the watchdog was armed, which should exceed the timer period. + // We don't actually know the elapsed number of ticks, so let's return + // the timer period plus 1. + // + if (mWatchdogNotify != NULL) { + TimerPeriod = ((TIME_UNITS_PER_SECOND / mTimerFrequencyHz) * mNumTimerTicks); + mWatchdogNotify (TimerPeriod + 1); + } + + gRT->ResetSystem (EfiResetCold, EFI_TIMEOUT, StrSize (ResetString), + (CHAR16 *)ResetString); // If we got here then the reset didn't work ASSERT (FALSE); @@ -141,16 +156,24 @@ WatchdogInterruptHandler ( @retval EFI_UNSUPPORTED The code does not support NotifyFunction. **/ +STATIC EFI_STATUS EFIAPI WatchdogRegisterHandler ( - IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction ) { - // ERROR: This function is not supported. - // The watchdog will reset the board - return EFI_UNSUPPORTED; + if (mWatchdogNotify == NULL && NotifyFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mWatchdogNotify != NULL && NotifyFunction != NULL) { + return EFI_ALREADY_STARTED; + } + + mWatchdogNotify = NotifyFunction; + return EFI_SUCCESS; } /** @@ -167,10 +190,11 @@ WatchdogRegisterHandler ( in TimerPeriod 100ns units. **/ +STATIC EFI_STATUS EFIAPI WatchdogSetTimerPeriod ( - IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, IN UINT64 TimerPeriod // In 100ns units ) { @@ -222,10 +246,11 @@ WatchdogSetTimerPeriod ( @retval EFI_INVALID_PARAMETER TimerPeriod is NULL. **/ +STATIC EFI_STATUS EFIAPI WatchdogGetTimerPeriod ( - IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, + IN EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This, OUT UINT64 *TimerPeriod ) { @@ -270,13 +295,13 @@ WatchdogGetTimerPeriod ( Retrieves the period of the timer interrupt in 100ns units. **/ -EFI_WATCHDOG_TIMER_ARCH_PROTOCOL gWatchdogTimer = { - (EFI_WATCHDOG_TIMER_REGISTER_HANDLER)WatchdogRegisterHandler, - (EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD)WatchdogSetTimerPeriod, - (EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD)WatchdogGetTimerPeriod +STATIC EFI_WATCHDOG_TIMER_ARCH_PROTOCOL mWatchdogTimer = { + WatchdogRegisterHandler, + WatchdogSetTimerPeriod, + WatchdogGetTimerPeriod }; -EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL; +STATIC EFI_EVENT mEfiExitBootServicesEvent; EFI_STATUS EFIAPI @@ -288,6 +313,10 @@ GenericWatchdogEntry ( EFI_STATUS Status; EFI_HANDLE Handle; + Status = gBS->LocateProtocol (&gHardwareInterrupt2ProtocolGuid, NULL, + (VOID **)&mInterruptProtocol); + ASSERT_EFI_ERROR (Status); + /* Make sure the Watchdog Timer Architectural Protocol has not been installed in the system yet. This will avoid conflicts with the universal watchdog */ @@ -296,51 +325,45 @@ GenericWatchdogEntry ( mTimerFrequencyHz = ArmGenericTimerGetTimerFreq (); ASSERT (mTimerFrequencyHz != 0); - // Register for an ExitBootServicesEvent - Status = gBS->CreateEvent ( - EVT_SIGNAL_EXIT_BOOT_SERVICES, - TPL_NOTIFY, - WatchdogExitBootServicesEvent, - NULL, - &EfiExitBootServicesEvent - ); - if (!EFI_ERROR (Status)) { - // Install interrupt handler - Status = gBS->LocateProtocol ( - &gHardwareInterrupt2ProtocolGuid, - NULL, - (VOID **)&mInterruptProtocol - ); - if (!EFI_ERROR (Status)) { - Status = mInterruptProtocol->RegisterInterruptSource ( - mInterruptProtocol, - FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum), - WatchdogInterruptHandler - ); - if (!EFI_ERROR (Status)) { - Status = mInterruptProtocol->SetTriggerType ( - mInterruptProtocol, - FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum), - EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING - ); - if (!EFI_ERROR (Status)) { - // Install the Timer Architectural Protocol onto a new handle - Handle = NULL; - Status = gBS->InstallMultipleProtocolInterfaces ( - &Handle, - &gEfiWatchdogTimerArchProtocolGuid, - &gWatchdogTimer, - NULL - ); - } - } - } + // Install interrupt handler + Status = mInterruptProtocol->RegisterInterruptSource (mInterruptProtocol, + FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum), + WatchdogInterruptHandler); + if (EFI_ERROR (Status)) { + return Status; } + Status = mInterruptProtocol->SetTriggerType (mInterruptProtocol, + FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum), + EFI_HARDWARE_INTERRUPT2_TRIGGER_EDGE_RISING); + if (EFI_ERROR (Status)) { + goto UnregisterHandler; + } + + // Install the Timer Architectural Protocol onto a new handle + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces (&Handle, + &gEfiWatchdogTimerArchProtocolGuid, &mWatchdogTimer, + NULL); + if (EFI_ERROR (Status)) { + goto UnregisterHandler; + } + + // Register for an ExitBootServicesEvent + Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, + WatchdogExitBootServicesEvent, NULL, + &mEfiExitBootServicesEvent); ASSERT_EFI_ERROR (Status); mNumTimerTicks = 0; WatchdogDisable (); + return EFI_SUCCESS; + +UnregisterHandler: + // Unregister the handler + mInterruptProtocol->RegisterInterruptSource (mInterruptProtocol, + FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum), + NULL); return Status; }