From patchwork Tue Dec 18 13:10:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 154140 Delivered-To: patch@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp3690457ljp; Tue, 18 Dec 2018 05:10:26 -0800 (PST) X-Google-Smtp-Source: AFSGD/UpLLScK07mWmxhnjZ1c0LXJVxFhtKRDqXZA9JsQO9xnruk865bYCYUeSNHtFfL5gj/NEBF X-Received: by 2002:a63:7c13:: with SMTP id x19mr14758692pgc.336.1545138626578; Tue, 18 Dec 2018 05:10:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1545138626; cv=none; d=google.com; s=arc-20160816; b=flk2t+rgX6GZAb93rH2Wzp6t348axa6CsnWqBLbBtZ517HdkfRHyUjWXB5AO1ky8bL 61cADTQeMQ1TbBlrk3CrATaABXAtB4AEcPrrqWaIhjB6N+ZF+UnvHaMLyE3+vmYr4JL/ u/aenvme8QfbC0/E4SkfuN+qk8t85OEJ4XM9BZJbaCzSnB5TlWc5zFG6PCBiaTsV3nbU kEColMMsTtp0H44SB7OiReTyfC+bkl8Q1XE5s4ytSXqqX/r1oEvqcrNZ6K91H5TTpt4t ajbgeFgGQ9XQ3O9CvgOsMr3S5VxqlfjWvuC9oyUrax51OlBZZrfftGXKQXNKKZPOKRtH 6Gww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to; bh=1ZEtI9CKNSbJf1BSkx0VLPco8daCsLwspaTNqYwGFJ0=; b=eK85HoK4MSQc+fk8vB3SwPiaC+HFAkI1HuTPGz6slNfvJ+NZu3lq/eein765RW1Ky2 9093WWO+dHPFMsQfoEBsoqfhyFORw5q4c22GQ4jaT6QyVrk2EWQBI6LbvtIy3eKRN9+o PVzZEJiVr6TzPFhqLFVW/OQaJdfJT5Cu6TJEuGduth2OTcno4iTgSH5QzozNCdqsKngU Gynhmoai5K735duF4vVxKRWrmwCZBDT3yq06cmgewEixPwXCb9Bhh8D0R+1zDPn+w5pr maD8zxRYatcfgv8RiqZzVAIFhSbx9O6yGYII/elesy0y+heR5NMvtLe2C/ylepnWueje fv1w== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Rxw1hYwG; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from ml01.01.org (ml01.01.org. [2001:19d0:306:5::1]) by mx.google.com with ESMTPS id k19si10592946pgn.20.2018.12.18.05.10.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 18 Dec 2018 05:10:26 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) client-ip=2001:19d0:306:5::1; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Rxw1hYwG; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 2001:19d0:306:5::1 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id C01FF2119EF4A; Tue, 18 Dec 2018 05:10:23 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:4864:20::542; helo=mail-ed1-x542.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-ed1-x542.google.com (mail-ed1-x542.google.com [IPv6:2a00:1450:4864:20::542]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 3B8442119AC2B for ; Tue, 18 Dec 2018 05:10:22 -0800 (PST) Received: by mail-ed1-x542.google.com with SMTP id b3so13842382ede.1 for ; Tue, 18 Dec 2018 05:10:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=NfIBw6OCuzPvpeUBiyRYvzBcvOIY4kpxB6UjFI2CzPo=; b=Rxw1hYwGER8kwFImI9AeTT6lKZayaaEL5j1PDhYeEum62ZjjMMk9wLt5Z5ZCxiW3WX i+lc7vkMcRnPGjsZr4njCHJnVI4QP813XYwWHLGLws7ZTlnr527SwNn1e4pWDjdlgVog iwqmXf/K/Nw3rtYs4eIUv4QcRs4DgezSwXZFo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=NfIBw6OCuzPvpeUBiyRYvzBcvOIY4kpxB6UjFI2CzPo=; b=tpwj80/naXMBYSrmUIvveHjTcKLjnYodw1J1GWtCqvy40dgKhWZckumfHrx7GbdWz/ EHLbU3drbVK4rewQHxVpAAlccPylDTUVgHZprfmUjDHL9JQHqgqikmcZ62/BaR4keuBk NjpD3s2OBc7/DSQJocWPVO+7JlAdoQNYWc5OiJzLEopI3c5kNixPF+ADik/zl6bBwxMZ R+wqtkTguupCxxSsSLFtl3daHCMyccLiCcZNW8ufOzlhlK2/KRed/oID/WmzOM75Si29 bR1X3iYePtogBBgsuAUpUJ1Lg6Cu6Al8RaXr4rbYX+Ee68U6473jxJ5VPRWmHjZabIiH zHkQ== X-Gm-Message-State: AA+aEWZTu9QiYo6ZdtCSyB2X9J52BMvt0CwaraXdv6RXumgMqHHTikFA Bv01LOZi1q0jrJikc8Kcgm9Bja0j5248uPpX X-Received: by 2002:a50:ac19:: with SMTP id v25mr16616588edc.218.1545138620263; Tue, 18 Dec 2018 05:10:20 -0800 (PST) Received: from mba13.arnhem.chello.nl (dhcp-077-251-017-237.chello.nl. [77.251.17.237]) by smtp.gmail.com with ESMTPSA id f6sm4384755ede.53.2018.12.18.05.10.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 18 Dec 2018 05:10:19 -0800 (PST) From: Ard Biesheuvel To: edk2-devel@lists.01.org Date: Tue, 18 Dec 2018 14:10:12 +0100 Message-Id: <20181218131015.20062-3-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181218131015.20062-1-ard.biesheuvel@linaro.org> References: <20181218131015.20062-1-ard.biesheuvel@linaro.org> Subject: [edk2] [PATCH 2/4] ArmPlatformPkg/SP805WatchdogDxe: switch to interrupt mode X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" The SP805 watchdog driver doesn't implement the PI watchdog protocol fully, but always simply resets the system if the watchdog time runs out. However, the hardware does support the intended usage model, as long as the SP805 is wired up correctly. So let's implement interrupt based mode involving a handler that is registered by the DXE core and invoked when the watchdog runs out. In the interrupt handler, we invoke the notify function if one was registered, or call the ResetSystem() runtime service otherwise (as per the UEFI spec) Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel --- ArmPlatformPkg/ArmPlatformPkg.dec | 1 + ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805Watchdog.c | 95 ++++++++++++++------ ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805WatchdogDxe.inf | 6 +- 3 files changed, 75 insertions(+), 27 deletions(-) -- 2.17.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec index 5f67e7415469..44c00bd0c133 100644 --- a/ArmPlatformPkg/ArmPlatformPkg.dec +++ b/ArmPlatformPkg/ArmPlatformPkg.dec @@ -70,6 +70,7 @@ ## SP805 Watchdog gArmPlatformTokenSpaceGuid.PcdSP805WatchdogBase|0x0|UINT32|0x00000023 gArmPlatformTokenSpaceGuid.PcdSP805WatchdogClockFrequencyInHz|32000|UINT32|0x00000021 + gArmPlatformTokenSpaceGuid.PcdSP805WatchdogInterrupt|0|UINT32|0x0000002E ## PL011 UART gArmPlatformTokenSpaceGuid.PL011UartClkInHz|24000000|UINT32|0x0000001F diff --git a/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805Watchdog.c b/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805Watchdog.c index 12c2f0a1fe49..4f09acf1fa28 100644 --- a/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805Watchdog.c +++ b/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805Watchdog.c @@ -21,12 +21,17 @@ #include #include #include +#include +#include #include #include "SP805Watchdog.h" -STATIC EFI_EVENT mEfiExitBootServicesEvent; +STATIC EFI_EVENT mEfiExitBootServicesEvent; +STATIC EFI_HARDWARE_INTERRUPT_PROTOCOL *mInterrupt; +STATIC EFI_WATCHDOG_TIMER_NOTIFY mWatchdogNotify; +STATIC UINT32 mTimerPeriod; /** Make sure the SP805 registers are unlocked for writing. @@ -65,6 +70,33 @@ SP805Lock ( } } +STATIC +VOID +EFIAPI +SP805InterruptHandler ( + IN HARDWARE_INTERRUPT_SOURCE Source, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ + // + // 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) { + mWatchdogNotify (mTimerPeriod + 1); + } else { + gRT->ResetSystem (EfiResetCold, EFI_TIMEOUT, 0, NULL); + } + + SP805Unlock (); + MmioWrite32 (SP805_WDOG_INT_CLR_REG, 0); // write of any value clears the irq + SP805Lock (); + + mInterrupt->EndOfInterrupt (mInterrupt, Source); +} + /** Stop the SP805 watchdog timer from counting down by disabling interrupts. **/ @@ -149,9 +181,16 @@ SP805RegisterHandler ( IN EFI_WATCHDOG_TIMER_NOTIFY NotifyFunction ) { - // ERROR: This function is not supported. - // The hardware watchdog will reset the board - return EFI_INVALID_PARAMETER; + if (mWatchdogNotify == NULL && NotifyFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mWatchdogNotify != NULL && NotifyFunction != NULL) { + return EFI_ALREADY_STARTED; + } + + mWatchdogNotify = NotifyFunction; + return EFI_SUCCESS; } /** @@ -202,19 +241,16 @@ SP805SetTimerPeriod ( SP805Stop (); } else { // Calculate the Watchdog ticks required for a delay of (TimerTicks * 100) nanoseconds - // The SP805 will count down to ZERO once, generate an interrupt and - // then it will again reload the initial value and start again. - // On the second time when it reaches ZERO, it will actually reset the board. - // Therefore, we need to load half the required delay. + // The SP805 will count down to zero and generate an interrupt. // - // WatchdogTicks = ((TimerPeriod * 100 * SP805_CLOCK_FREQUENCY) / 1GHz) / 2 ; + // WatchdogTicks = ((TimerPeriod * 100 * SP805_CLOCK_FREQUENCY) / 1GHz); // // i.e.: // - // WatchdogTicks = (TimerPeriod * SP805_CLOCK_FREQUENCY) / 20 MHz ; + // WatchdogTicks = (TimerPeriod * SP805_CLOCK_FREQUENCY) / 10 MHz ; Ticks64bit = MultU64x32 (TimerPeriod, PcdGet32 (PcdSP805WatchdogClockFrequencyInHz)); - Ticks64bit = DivU64x32 (Ticks64bit, 20000000); + Ticks64bit = DivU64x32 (Ticks64bit, 10 * 1000 * 1000); // The registers in the SP805 are only 32 bits if (Ticks64bit > MAX_UINT32) { @@ -233,9 +269,12 @@ SP805SetTimerPeriod ( SP805Start (); } + mTimerPeriod = TimerPeriod; + EXIT: // Ensure the watchdog is locked before exiting. SP805Lock (); + ASSERT_EFI_ERROR (Status); return Status; } @@ -262,25 +301,11 @@ SP805GetTimerPeriod ( OUT UINT64 *TimerPeriod ) { - UINT64 ReturnValue; - if (TimerPeriod == NULL) { return EFI_INVALID_PARAMETER; } - // Check if the watchdog is stopped - if ((MmioRead32 (SP805_WDOG_CONTROL_REG) & SP805_WDOG_CTRL_INTEN) == 0) { - // It is stopped, so return zero. - ReturnValue = 0; - } else { - // Convert the Watchdog ticks into TimerPeriod - // Ensure 64bit arithmetic throughout because the Watchdog ticks may already - // be at the maximum 32 bit value and we still need to multiply that by 600. - ReturnValue = MultU64x32 (MmioRead32 (SP805_WDOG_LOAD_REG), 600); - } - - *TimerPeriod = ReturnValue; - + *TimerPeriod = mTimerPeriod; return EFI_SUCCESS; } @@ -343,6 +368,11 @@ SP805Initialize ( EFI_STATUS Status; EFI_HANDLE Handle; + // Find the interrupt controller protocol. ASSERT if not found. + Status = gBS->LocateProtocol (&gHardwareInterruptProtocolGuid, NULL, + (VOID **)&mInterrupt); + ASSERT_EFI_ERROR (Status); + // Unlock access to the SP805 registers SP805Unlock (); @@ -350,13 +380,26 @@ SP805Initialize ( SP805Stop (); // Set the watchdog to reset the board when triggered + // This is a last resort in case the interrupt handler fails if ((MmioRead32 (SP805_WDOG_CONTROL_REG) & SP805_WDOG_CTRL_RESEN) == 0) { MmioOr32 (SP805_WDOG_CONTROL_REG, SP805_WDOG_CTRL_RESEN); } + // Clear any pending interrupts + MmioWrite32 (SP805_WDOG_INT_CLR_REG, 0); // write of any value clears the irq + // Prohibit any rogue access to SP805 registers SP805Lock (); + Status = mInterrupt->RegisterInterruptSource (mInterrupt, + PcdGet32 (PcdSP805WatchdogInterrupt), + SP805InterruptHandler); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: failed to register watchdog interrupt - %r\n", + __FUNCTION__, Status)); + return Status; + } + // // Make sure the Watchdog Timer Architectural Protocol has not been installed in the system yet. // This will avoid conflicts with the universal watchdog diff --git a/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805WatchdogDxe.inf b/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805WatchdogDxe.inf index 99ecab477567..1373e267612f 100644 --- a/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805WatchdogDxe.inf +++ b/ArmPlatformPkg/Drivers/SP805WatchdogDxe/SP805WatchdogDxe.inf @@ -27,6 +27,7 @@ [Packages] ArmPlatformPkg/ArmPlatformPkg.dec ArmPkg/ArmPkg.dec + EmbeddedPkg/EmbeddedPkg.dec MdePkg/MdePkg.dec [LibraryClasses] @@ -35,13 +36,16 @@ IoLib UefiBootServicesTableLib UefiDriverEntryPoint + UefiRuntimeServicesTableLib [Pcd] gArmPlatformTokenSpaceGuid.PcdSP805WatchdogBase gArmPlatformTokenSpaceGuid.PcdSP805WatchdogClockFrequencyInHz + gArmPlatformTokenSpaceGuid.PcdSP805WatchdogInterrupt [Protocols] + gHardwareInterruptProtocolGuid ## ALWAYS_CONSUMES gEfiWatchdogTimerArchProtocolGuid ## ALWAYS_PRODUCES [Depex] - TRUE + gHardwareInterruptProtocolGuid