From: "Leif Lindholm" <leif@nuviainc.com>
To: Nhi Pham <nhi@os.amperecomputing.com>
Cc: devel@edk2.groups.io, patches@amperecomputing.com,
vunguyen@os.amperecomputing.com,
Thang Nguyen <thang@os.amperecomputing.com>,
Chuong Tran <chuong@os.amperecomputing.com>,
Phong Vo <phong@os.amperecomputing.com>,
Michael D Kinney <michael.d.kinney@intel.com>,
Ard Biesheuvel <ardb+tianocore@kernel.org>,
Nate DeSimone <nathaniel.l.desimone@intel.com>
Subject: Re: [edk2-platforms][PATCH v4 03/31] AmpereAltraPkg: Add FailSafe and WDT support
Date: Tue, 26 Oct 2021 13:15:53 +0100 [thread overview]
Message-ID: <20211026121553.rm6l6dvoztjd3o3c@leviathan> (raw)
In-Reply-To: <20211022061809.31087-4-nhi@os.amperecomputing.com>
Hi Nhi,
On Fri, Oct 22, 2021 at 13:17:41 +0700, Nhi Pham wrote:
> The FailSafeDxe is a driver for the FailSafe feature which reverts the
> system's configuration to known good values if the system fails to boot
> up multiple times. Also, this driver implements the Watchdog Timer
> Architectural Protocol to reset the system if it hangs, which is
> implemented by the MdeModulePkg/Universal/WatchdogTimerDxe module. So,
> the WDT is now used exclusively by the FailSafeDxe.
I guess I skimmed this message previously. Taking a closer look, I am
very confused by this design (and the commit message), on several
levels.
1) Why do you need a custom watchdog driver?
2) Why is it integrated into FailSafeDxe instead of being a standalone
driver?
3) Given that it's integrated, why do you install it as an
implementation of EFI_WATCHDOG_TIMER_ARCH_PROTOCOL?
4) Given that it's installed, how can it be exclusively for the use of
FailSafeDxe?
> By default, when system starts, it configures the secure watchdog timer
> with a default value of 5 minutes. If the system boots up cleanly to the
> considered good stage, the counter is cleared as it indicates FailSafe
> monitor (ATF) that has booted up successfully. If the timer expires, it
> is considered a failed boot and the system is rebooted.
How?
(more below)
> Cc: Thang Nguyen <thang@os.amperecomputing.com>
> Cc: Chuong Tran <chuong@os.amperecomputing.com>
> Cc: Phong Vo <phong@os.amperecomputing.com>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
>
> Signed-off-by: Nhi Pham <nhi@os.amperecomputing.com>
> Reviewed-by: Leif Lindholm <leif@nuviainc.com>
> ---
> Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 6 +-
> Platform/Ampere/JadePkg/Jade.fdf | 6 +-
> Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.inf | 51 +++
> Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafe.h | 44 +++
> Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.h | 29 ++
> Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.c | 243 +++++++++++++
> Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.c | 357 ++++++++++++++++++++
> 7 files changed, 734 insertions(+), 2 deletions(-)
>
> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> index 69a6caa56752..bfe66f332c56 100644
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> @@ -588,7 +588,11 @@ [Components.common]
> # Timer
> #
> ArmPkg/Drivers/TimerDxe/TimerDxe.inf
> - MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
> +
> + #
> + # FailSafe and Watchdog Timer
> + #
> + Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
>
> #
> # ARM GIC Dxe
> diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
> index 6e228d4ecb89..49e38db1bce4 100644
> --- a/Platform/Ampere/JadePkg/Jade.fdf
> +++ b/Platform/Ampere/JadePkg/Jade.fdf
> @@ -185,7 +185,11 @@ [FV.FvMain]
> # Timer
> #
> INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
> - INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
> +
> + #
> + # FailSafe and Watchdog Timer
> + #
> + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
>
> #
> # ARM GIC Dxe
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
> new file mode 100644
> index 000000000000..cea69516d0bb
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.inf
> @@ -0,0 +1,51 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = FailSafeDxe
> + FILE_GUID = 7BC4F970-B1CF-11E6-80F5-76304DEC7EB7
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 1.0
> + ENTRY_POINT = FailSafeDxeEntryPoint
> +
> +[Sources]
> + FailSafe.h
> + FailSafeDxe.c
> + Watchdog.c
> + Watchdog.h
> +
> +[Packages]
> + ArmPkg/ArmPkg.dec
> + ArmPlatformPkg/ArmPlatformPkg.dec
> + EmbeddedPkg/EmbeddedPkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> + Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +
> +[LibraryClasses]
> + DebugLib
> + FlashLib
> + IoLib
> + NVParamLib
> + TimerLib
> + UefiBootServicesTableLib
> + UefiDriverEntryPoint
> + UefiLib
> +
> +[Pcd]
> + gArmTokenSpaceGuid.PcdGenericWatchdogControlBase
> + gArmTokenSpaceGuid.PcdGenericWatchdogEl2IntrNum
> +
> +[Protocols]
> + gEfiWatchdogTimerArchProtocolGuid ## PRODUCES
> + gHardwareInterrupt2ProtocolGuid ## CONSUMES
> +
> +[Depex]
> + gHardwareInterrupt2ProtocolGuid
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafe.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafe.h
> new file mode 100644
> index 000000000000..911b093dce28
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafe.h
> @@ -0,0 +1,44 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef FAILSAFE_H_
> +#define FAILSAFE_H_
> +
> +#define FAILSAFE_BOOT_NORMAL 0x00
> +#define FAILSAFE_BOOT_LAST_KNOWN_SETTINGS 0x01
> +#define FAILSAFE_BOOT_DEFAULT_SETTINGS 0x02
> +#define FAILSAFE_BOOT_DDR_DOWNGRADE 0x03
> +#define FAILSAFE_BOOT_SUCCESSFUL 0x04
> +
> +#pragma pack(1)
> +typedef struct {
> + UINT8 ImgMajorVer;
> + UINT8 ImgMinorVer;
> + UINT32 NumRetry1;
> + UINT32 NumRetry2;
> + UINT32 MaxRetry;
> + UINT8 Status;
> + //
> + // Byte[3]: Reserved
> + // Byte[2]: Slave MCU Failure Mask
> + // Byte[1]: Reserved
> + // Byte[0]: Master MCU Failure Mask
> + //
> + UINT32 MCUFailsMask;
> + UINT16 CRC16;
> + UINT8 Reserved[3];
> +} FAIL_SAFE_CONTEXT;
> +#pragma pack()
> +
> +BOOLEAN
> +EFIAPI
> +IsFailSafeOff (
> + VOID
> + );
> +
> +#endif /* FAILSAFE_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.h b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.h
> new file mode 100644
> index 000000000000..6c9106fdbea5
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.h
> @@ -0,0 +1,29 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef GENERIC_WATCHDOG_H_
> +#define GENERIC_WATCHDOG_H_
> +
> +#include <Protocol/WatchdogTimer.h>
> +
> +/* The number of 100ns periods (the unit of time passed to these functions)
> + in a second */
> +#define TIME_UNITS_PER_SECOND 10000000
> +
> +/**
> + The function to install Watchdog timer protocol to the system
> +
> + @retval Return EFI_SUCCESS if install Watchdog timer protocol successfully.
> + **/
> +EFI_STATUS
> +EFIAPI
> +WatchdogTimerInstallProtocol (
> + EFI_WATCHDOG_TIMER_ARCH_PROTOCOL **WatchdogTimerProtocol
> + );
> +
> +#endif /* GENERIC_WATCHDOG_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.c
> new file mode 100644
> index 000000000000..487e0d3870ab
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/FailSafeDxe.c
> @@ -0,0 +1,243 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/FlashLib.h>
> +#include <Library/NVParamLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <NVParamDef.h>
> +
> +#include "FailSafe.h"
> +#include "Watchdog.h"
> +
> +STATIC UINTN gWatchdogOSTimeout;
> +STATIC BOOLEAN gFailSafeOff;
> +STATIC EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *gWatchdogTimer;
> +
> +STATIC
> +INTN
> +CheckCrc16 (
> + UINT8 *Pointer,
> + INTN Count
> + )
> +{
> + INTN Crc = 0;
> + INTN Index;
> +
> + while (--Count >= 0) {
> + Crc = Crc ^ (INTN)*Pointer++ << 8;
> + for (Index = 0; Index < 8; ++Index) {
> + if ((Crc & 0x8000) != 0) {
> + Crc = Crc << 1 ^ 0x1021;
> + } else {
> + Crc = Crc << 1;
> + }
> + }
> + }
> +
> + return Crc & 0xFFFF;
> +}
> +
> +BOOLEAN
> +FailSafeValidCRC (
> + FAIL_SAFE_CONTEXT *FailSafeBuf
> + )
> +{
> + UINT8 Valid;
> + UINT16 Crc;
> + UINT32 Len;
> +
> + Len = sizeof (FAIL_SAFE_CONTEXT);
> + Crc = FailSafeBuf->CRC16;
> + FailSafeBuf->CRC16 = 0;
> +
> + Valid = (Crc == CheckCrc16 ((UINT8 *)FailSafeBuf, Len));
> + FailSafeBuf->CRC16 = Crc;
> +
> + return Valid;
> +}
> +
> +BOOLEAN
> +FailSafeFailureStatus (
> + UINT8 Status
> + )
> +{
> + if ((Status == FAILSAFE_BOOT_LAST_KNOWN_SETTINGS) ||
> + (Status == FAILSAFE_BOOT_DEFAULT_SETTINGS) ||
> + (Status == FAILSAFE_BOOT_DDR_DOWNGRADE)) {
> + return TRUE;
> + }
> +
> + return FALSE;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FailSafeBootSuccessfully (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + FAIL_SAFE_CONTEXT FailSafeBuf;
> + UINT32 FailSafeSize;
> + UINT64 FailSafeStartOffset;
> +
> + Status = FlashGetFailSafeInfo (&FailSafeStartOffset, &FailSafeSize);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: Failed to get context region information\n", __FUNCTION__));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = FlashReadCommand (FailSafeStartOffset, (UINT8 *)&FailSafeBuf, sizeof (FAIL_SAFE_CONTEXT));
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + //
> + // If failsafe context is valid, and:
> + // - The status indicate non-failure, then don't clear it
> + // - The status indicate a failure, then go and clear it
> + //
> + if (FailSafeValidCRC (&FailSafeBuf)
> + && !FailSafeFailureStatus (FailSafeBuf.Status)) {
> + return EFI_SUCCESS;
> + }
> +
> + Status = FlashEraseCommand (FailSafeStartOffset, FailSafeSize);
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +FailSafeTestBootFailure (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> + UINT32 Value = 0;
> +
> + //
> + // Simulate UEFI boot failure due to config wrong NVPARAM for
> + // testing failsafe feature
> + //
> + Status = NVParamGet (NV_SI_UEFI_FAILURE_FAILSAFE, NV_PERM_ALL, &Value);
> + if (!EFI_ERROR (Status) && (Value == 1)) {
> + CpuDeadLoop ();
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +VOID
> +FailSafeTurnOff (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> +
> + if (IsFailSafeOff ()) {
> + return;
> + }
> +
> + Status = FailSafeBootSuccessfully ();
> + ASSERT_EFI_ERROR (Status);
> +
> + gFailSafeOff = TRUE;
> +
> + /* Disable Watchdog timer */
> + gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, 0);
> +}
> +
> +BOOLEAN
> +EFIAPI
> +IsFailSafeOff (
> + VOID
> + )
> +{
> + return gFailSafeOff;
> +}
> +
> +/**
> + The function to refresh Watchdog timer in the event before exiting boot services
> +**/
> +VOID
> +WdtTimerExitBootServiceCallback (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> +
> + /* Enable Watchdog timer for OS booting */
> + if (gWatchdogOSTimeout != 0) {
> + gWatchdogTimer->SetTimerPeriod (
> + gWatchdogTimer,
> + gWatchdogOSTimeout * TIME_UNITS_PER_SECOND
> + );
> + } else {
> + /* Disable Watchdog timer */
> + gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, 0);
> + }
> +}
> +
> +/**
> + Main entry for this driver.
> +
> + @param ImageHandle Image handle this driver.
> + @param SystemTable Pointer to SystemTable.
> +
> + @retval EFI_SUCCESS This function always complete successfully.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FailSafeDxeEntryPoint (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_EVENT ExitBootServicesEvent;
> + EFI_STATUS Status;
> +
> + gFailSafeOff = FALSE;
> +
> + FailSafeTestBootFailure ();
> +
> + /* We need to setup non secure Watchdog to ensure that the system will
> + * boot to OS successfully.
> + *
> + * The BIOS doesn't handle Watchdog interrupt so we expect WS1 asserted EL3
> + * when Watchdog timeout triggered
> + */
> +
> + Status = WatchdogTimerInstallProtocol (&gWatchdogTimer);
> + ASSERT_EFI_ERROR (Status);
> +
> + // We should register a callback function before entering to Setup screen
> + // rather than always call it at DXE phase.
> + FailSafeTurnOff ();
> +
> + /* Register event before exit boot services */
> + Status = gBS->CreateEvent (
> + EVT_SIGNAL_EXIT_BOOT_SERVICES,
> + TPL_NOTIFY,
> + WdtTimerExitBootServiceCallback,
> + NULL,
> + &ExitBootServicesEvent
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + return Status;
> +}
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.c
> new file mode 100644
> index 000000000000..34329d04206a
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FailSafeDxe/Watchdog.c
> @@ -0,0 +1,357 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/ArmGenericTimerCounterLib.h>
> +#include <Library/ArmLib.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/IoLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Protocol/HardwareInterrupt2.h>
> +
> +#include "FailSafe.h"
> +#include "Watchdog.h"
> +
> +/* Watchdog timer controller registers */
> +#define WDT_CTRL_BASE_REG FixedPcdGet64 (PcdGenericWatchdogControlBase)
> +#define WDT_CTRL_WCS_OFF 0x0
> +#define WDT_CTRL_WCS_ENABLE_MASK 0x1
> +#define WDT_CTRL_WOR_OFF 0x8
> +#define WDT_CTRL_WCV_OFF 0x10
> +#define WS0_INTERRUPT_SOURCE FixedPcdGet32 (PcdGenericWatchdogEl2IntrNum)
> +
> +STATIC UINT64 mNumTimerTicks;
> +STATIC EFI_HARDWARE_INTERRUPT2_PROTOCOL *mInterruptProtocol;
> +BOOLEAN mInterruptWS0Enabled;
> +
> +STATIC
> +VOID
> +WatchdogTimerWriteOffsetRegister (
> + UINT32 Value
> + )
> +{
> + MmioWrite32 (WDT_CTRL_BASE_REG + WDT_CTRL_WOR_OFF, Value);
> +}
> +
> +STATIC
> +VOID
> +WatchdogTimerWriteCompareRegister (
> + UINT64 Value
> + )
> +{
> + MmioWrite64 (WDT_CTRL_BASE_REG + WDT_CTRL_WCV_OFF, Value);
> +}
> +
> +STATIC
> +EFI_STATUS
> +WatchdogTimerEnable (
> + IN BOOLEAN Enable
> + )
> +{
> + UINT32 Val = MmioRead32 ((UINTN)(WDT_CTRL_BASE_REG + WDT_CTRL_WCS_OFF));
> +
> + if (Enable) {
> + Val |= WDT_CTRL_WCS_ENABLE_MASK;
> + } else {
> + Val &= ~WDT_CTRL_WCS_ENABLE_MASK;
> + }
> + MmioWrite32 ((UINTN)(WDT_CTRL_BASE_REG + WDT_CTRL_WCS_OFF), Val);
> +
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +WatchdogTimerSetup (
> + VOID
> + )
> +{
> + EFI_STATUS Status;
> +
> + /* Disable Watchdog timer */
> + WatchdogTimerEnable (FALSE);
> +
> + if (!mInterruptWS0Enabled) {
> + Status = mInterruptProtocol->EnableInterruptSource (
> + mInterruptProtocol,
> + WS0_INTERRUPT_SOURCE
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + mInterruptWS0Enabled = TRUE;
> + }
> +
> + if (mNumTimerTicks == 0) {
> + return EFI_SUCCESS;
> + }
> +
> + /* If the number of required ticks is greater than the max the Watchdog's
> + offset register (WOR) can hold, we need to manually compute and set
> + the compare register (WCV) */
> + if (mNumTimerTicks > MAX_UINT32) {
> + /* We need to enable the Watchdog *before* writing to the compare register,
> + because enabling the Watchdog causes an "explicit refresh", which
> + clobbers the compare register (WCV). In order to make sure this doesn't
> + trigger an interrupt, set the offset to max. */
> + WatchdogTimerWriteOffsetRegister (MAX_UINT32);
> + WatchdogTimerEnable (TRUE);
> + WatchdogTimerWriteCompareRegister (ArmGenericTimerGetSystemCount () + mNumTimerTicks);
> + } else {
> + WatchdogTimerWriteOffsetRegister ((UINT32)mNumTimerTicks);
> + WatchdogTimerEnable (TRUE);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +
> +/* This function is called when the Watchdog's first signal (WS0) goes high.
> + It uses the ResetSystem Runtime Service to reset the board.
> +*/
> +VOID
> +EFIAPI
> +WatchdogTimerInterruptHandler (
> + IN HARDWARE_INTERRUPT_SOURCE Source,
> + IN EFI_SYSTEM_CONTEXT SystemContext
> + )
> +{
> + STATIC CONST CHAR16 ResetString[]= L"The generic Watchdog timer ran out.";
> +
> + mInterruptProtocol->EndOfInterrupt (mInterruptProtocol, Source);
> +
> + if (!IsFailSafeOff ()) {
> + /* Not handling interrupt as ATF is monitoring it */
> + return;
> + }
> +
> + WatchdogTimerEnable (FALSE);
> +
> + gRT->ResetSystem (
> + EfiResetCold,
> + EFI_TIMEOUT,
> + StrSize (ResetString),
> + (VOID *)&ResetString
> + );
> +
> + /* If we got here then the reset didn't work */
> + ASSERT (FALSE);
> +}
> +
> +/**
> + This function registers the handler NotifyFunction so it is called every time
> + the Watchdog timer expires. It also passes the amount of time since the last
> + handler call to the NotifyFunction.
> + If NotifyFunction is not NULL and a handler is not already registered,
> + then the new handler is registered and EFI_SUCCESS is returned.
> + If NotifyFunction is NULL, and a handler is already registered,
> + then that handler is unregistered.
> + If an attempt is made to register a handler when a handler is already
> + registered, then EFI_ALREADY_STARTED is returned.
> + If an attempt is made to unregister a handler when a handler is not
> + registered, then EFI_INVALID_PARAMETER is returned.
> +
> + @param This The EFI_TIMER_ARCH_PROTOCOL instance.
> + @param NotifyFunction The function to call when a timer interrupt fires.
> + This function executes at TPL_HIGH_LEVEL. The DXE
> + Core will register a handler for the timer interrupt,
> + so it can know how much time has passed. This
> + information is used to signal timer based events.
> + NULL will unregister the handler.
> +
> + @retval EFI_UNSUPPORTED The code does not support NotifyFunction.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +WatchdogTimerRegisterHandler (
> + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
> + IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction
> + )
> +{
> + /* Not support. Watchdog will reset the board */
> + return EFI_UNSUPPORTED;
What you actually have here is a hardware watchdog. On timeout it
triggers a hardware reset.
The definition of EFI_WATCHDOG_TIMER_ARCH_PROTOCOL is explicitly
described in PI (1.7a) as "This protocol is used to implement the Boot
Service SetWatchdogTimer().".
Further down the definition, the following text
---
When the watchdog timer fires, control will be passed to a handler if
one has been registered. If no handler has been registered, or the
registered handler returns, then the system will be reset by calling
the Runtime Service ResetSystem().
---
means that a watchdog that triggers a hardware reset on timeout is
inappropriate as the back-end for this. It cannot fulfill the
requirements of this protocol.
I see nothing wrong with including a driver for this hardware watchdog
in your platform port, but:
- It should be a standalone driver.
- It should not register itself as an implementation of
EFI_WATCHDOG_TIMER_ARCH_PROTOCOL.
- The platform port will still need to include an *actual*
implementation of EFI_WATCHDOG_TIMER_ARCH_PROTOCOL.
/
Leif
> +}
> +
> +/**
> + This function sets the amount of time to wait before firing the Watchdog
> + timer to TimerPeriod 100ns units. If TimerPeriod is 0, then the Watchdog
> + timer is disabled.
> +
> + @param This The EFI_WATCHDOG_TIMER_ARCH_PROTOCOL instance.
> + @param TimerPeriod The amount of time in 100ns units to wait before
> + the Watchdog timer is fired. If TimerPeriod is zero,
> + then the Watchdog timer is disabled.
> +
> + @retval EFI_SUCCESS The Watchdog timer has been programmed to fire
> + in Time 100ns units.
> + @retval EFI_DEVICE_ERROR A Watchdog timer could not be programmed due
> + to a device error.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +WatchdogTimerSetPeriod (
> + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
> + IN UINT64 TimerPeriod // In 100ns units
> + )
> +{
> + mNumTimerTicks = (ArmGenericTimerGetTimerFreq () * TimerPeriod) / TIME_UNITS_PER_SECOND;
> +
> + if (!IsFailSafeOff ()) {
> + /* Not support Watchdog timer service until FailSafe is off as ATF is monitoring it */
> + return EFI_SUCCESS;
> + }
> +
> + return WatchdogTimerSetup ();
> +}
> +
> +/**
> + This function retrieves the period of timer interrupts in 100ns units,
> + returns that value in TimerPeriod, and returns EFI_SUCCESS. If TimerPeriod
> + is NULL, then EFI_INVALID_PARAMETER is returned. If a TimerPeriod of 0 is
> + returned, then the timer is currently disabled.
> +
> + @param This The EFI_TIMER_ARCH_PROTOCOL instance.
> + @param TimerPeriod A pointer to the timer period to retrieve in
> + 100ns units. If 0 is returned, then the timer is
> + currently disabled.
> +
> +
> + @retval EFI_SUCCESS The timer period was returned in TimerPeriod.
> + @retval EFI_INVALID_PARAMETER TimerPeriod is NULL.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +WatchdogTimerGetPeriod (
> + IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
> + OUT UINT64 *TimerPeriod
> + )
> +{
> + if (TimerPeriod == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + *TimerPeriod = ((TIME_UNITS_PER_SECOND / ArmGenericTimerGetTimerFreq ()) * mNumTimerTicks);
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Interface structure for the Watchdog Architectural Protocol.
> +
> + @par Protocol Description:
> + This protocol provides a service to set the amount of time to wait
> + before firing the Watchdog timer, and it also provides a service to
> + register a handler that is invoked when the Watchdog timer fires.
> +
> + @par When the Watchdog timer fires, control will be passed to a handler
> + if one has been registered. If no handler has been registered,
> + or the registered handler returns, then the system will be
> + reset by calling the Runtime Service ResetSystem().
> +
> + @param RegisterHandler
> + Registers a handler that will be called each time the
> + Watchdogtimer interrupt fires. TimerPeriod defines the minimum
> + time between timer interrupts, so TimerPeriod will also
> + be the minimum time between calls to the registered
> + handler.
> + NOTE: If the Watchdog resets the system in hardware, then
> + this function will not have any chance of executing.
> +
> + @param SetTimerPeriod
> + Sets the period of the timer interrupt in 100ns units.
> + This function is optional, and may return EFI_UNSUPPORTED.
> + If this function is supported, then the timer period will
> + be rounded up to the nearest supported timer period.
> +
> + @param GetTimerPeriod
> + Retrieves the period of the timer interrupt in 100ns units.
> +
> +**/
> +STATIC EFI_WATCHDOG_TIMER_ARCH_PROTOCOL gWatchdogTimer = {
> + (EFI_WATCHDOG_TIMER_REGISTER_HANDLER)WatchdogTimerRegisterHandler,
> + (EFI_WATCHDOG_TIMER_SET_TIMER_PERIOD)WatchdogTimerSetPeriod,
> + (EFI_WATCHDOG_TIMER_GET_TIMER_PERIOD)WatchdogTimerGetPeriod
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +WatchdogTimerInstallProtocol (
> + EFI_WATCHDOG_TIMER_ARCH_PROTOCOL **WatchdogTimerProtocol
> + )
> +{
> + EFI_STATUS Status;
> + EFI_HANDLE Handle;
> + EFI_TPL CurrentTpl;
> +
> + /* Make sure the Watchdog Timer Architectural Protocol has not been installed
> + in the system yet.
> + This will avoid conflicts with the universal Watchdog */
> + ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiWatchdogTimerArchProtocolGuid);
> +
> + ASSERT (ArmGenericTimerGetTimerFreq () != 0);
> +
> + /* Install interrupt handler */
> + Status = gBS->LocateProtocol (
> + &gHardwareInterrupt2ProtocolGuid,
> + NULL,
> + (VOID **)&mInterruptProtocol
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + /*
> + * We don't want to be interrupted while registering Watchdog interrupt source as the interrupt
> + * may be trigger in the middle because the interrupt line already enabled in the EL3.
> + */
> + CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
> +
> + Status = mInterruptProtocol->RegisterInterruptSource (
> + mInterruptProtocol,
> + WS0_INTERRUPT_SOURCE,
> + WatchdogTimerInterruptHandler
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + /* Don't enable interrupt until FailSafe off */
> + mInterruptWS0Enabled = FALSE;
> + Status = mInterruptProtocol->DisableInterruptSource (
> + mInterruptProtocol,
> + WS0_INTERRUPT_SOURCE
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + gBS->RestoreTPL (CurrentTpl);
> +
> + Status = mInterruptProtocol->SetTriggerType (
> + mInterruptProtocol,
> + WS0_INTERRUPT_SOURCE,
> + EFI_HARDWARE_INTERRUPT2_TRIGGER_LEVEL_HIGH
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + /* Install the Timer Architectural Protocol onto a new handle */
> + Handle = NULL;
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &Handle,
> + &gEfiWatchdogTimerArchProtocolGuid,
> + &gWatchdogTimer,
> + NULL
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + mNumTimerTicks = 0;
> +
> + if (WatchdogTimerProtocol != NULL) {
> + *WatchdogTimerProtocol = &gWatchdogTimer;
> + }
> +
> + return Status;
> +}
> --
> 2.17.1
>
next prev parent reply other threads:[~2021-10-26 12:15 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-22 6:17 [edk2-platforms][PATCH v4 00/31] Add new Ampere Mt. Jade platform Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 01/31] Ampere: Initial support for Ampere Altra processor and " Nhi Pham
2021-10-26 11:14 ` Leif Lindholm
2021-11-03 9:31 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 02/31] AmpereAltraPkg: Add FlashLib library instance Nhi Pham
2021-10-26 11:25 ` Leif Lindholm
2021-11-03 9:32 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 03/31] AmpereAltraPkg: Add FailSafe and WDT support Nhi Pham
2021-10-26 12:15 ` Leif Lindholm [this message]
2021-11-03 9:35 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 04/31] AmpereAltraPkg: Add DwI2cLib library instance Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 05/31] AmpereAltraPkg: Add DwGpioLib " Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 06/31] JadePkg: Implement RealTimeClockLib for PCF85063 Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 07/31] AmpereAltraPkg: Add BootProgress support Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 08/31] AmpereAltraPkg: Support UEFI non-volatile variable Nhi Pham
2021-10-26 12:21 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 09/31] AmpereSiliconPkg: Add PlatformManagerUiLib library instance Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 10/31] AmpereAltraPkg, JadePkg: Add ACPI support Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 11/31] AmpereAltraPkg: Add Root Complex HOB data structures Nhi Pham
2021-10-26 12:23 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 12/31] AmpereAltraPkg: Add Ac01PcieLib library instance Nhi Pham
2021-10-26 12:45 ` Leif Lindholm
2021-11-03 9:33 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 13/31] JadePkg: Add BoardPcieLib " Nhi Pham
2021-10-26 12:46 ` Leif Lindholm
2021-11-03 9:33 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 14/31] AmpereAltraPkg: Add driver to initialize PCIe Root Complex Nhi Pham
2021-10-26 12:49 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 15/31] AmpereAltraPkg: Add PciHostBridgeLib library instance Nhi Pham
2021-10-26 12:49 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 16/31] AmpereAltraPkg: Add PciSegmentLib " Nhi Pham
2021-10-26 12:53 ` Leif Lindholm
2021-11-03 9:35 ` Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 17/31] JadePkg: Enable PciHostBridgeDxe driver Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 18/31] JadePkg: Add PciPlatformDxe driver Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 19/31] JadePkg: Add ACPI tables to support PCIe Nhi Pham
2021-10-26 12:54 ` Leif Lindholm
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 20/31] JadePkg: Add ASpeed GOP driver Nhi Pham
2021-10-22 6:17 ` [edk2-platforms][PATCH v4 21/31] AmpereAltraPkg: Add Random Number Generator Support Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 22/31] JadePkg: Add SMBIOS tables support Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 23/31] AmpereAltraPkg: Add DebugInfoPei module Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 24/31] AmpereAltraPkg: Add configuration screen for PCIe Nhi Pham
2021-10-26 12:56 ` Leif Lindholm
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 25/31] Ampere: Utilize the PCIe User setting Nhi Pham
2021-10-26 12:57 ` Leif Lindholm
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 26/31] AmpereAltraPkg: Add platform info screen Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 27/31] AmpereAltraPkg: Add configuration screen for Memory Nhi Pham
2021-10-26 12:58 ` Leif Lindholm
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 28/31] AmpereAltraPkg: Add configuration screen for CPU Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 29/31] AmpereAltraPkg: Add configuration screen for ACPI Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 30/31] AmpereAltraPkg: Add configuration screen for RAS Nhi Pham
2021-10-22 6:18 ` [edk2-platforms][PATCH v4 31/31] AmpereAltraPkg: Add configuration screen for Watchdog timer Nhi Pham
2021-10-26 13:03 ` Leif Lindholm
2021-11-03 9:36 ` Nhi Pham
2021-10-26 13:08 ` [edk2-platforms][PATCH v4 00/31] Add new Ampere Mt. Jade platform Leif Lindholm
2021-11-03 9:37 ` Nhi Pham
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211026121553.rm6l6dvoztjd3o3c@leviathan \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox