Hi Charles, Great thanks for your info. Sorry, I just see this message. Would you please provide some info about How to use the WS0/1. What is the original thought of this two stage timeout? Those info is very important for implementing this driver. :-) Thanks again! On 28 May 2015 at 05:47, administrator <charles.garcia-tobin@xxxxxxx> wrote: > Hi > > On 5/26/15, 6:11 PM, "Al Stone" <al.stone@xxxxxxxxxx> wrote: > >>On 05/22/2015 04:52 PM, Timur Tabi wrote: >>> The ARM Server Base System Architecture is a specification for ARM-based >>> server systems. Among other things, it defines the behavior and >>>register >>> interface for a watchdog timer. >>> >>> Signed-off-by: Timur Tabi <timur@xxxxxxxxxxxxxx> >>> --- >> >>My apologies for not getting a chance to think through earlier versions >>before now. >> >>So, this is meant to be SBSA compliant; is it also meant to be SBBR >>compliant? >>I suspect not, since there is no ACPI initialization and SBBR requires >>both >>UEFI and ACPI. Is there any reason for not being SBBR compliant? I'm not >>saying this is good or bad; I'm only trying to understand the reasoning. >> >>I'll also admit that I'm not an expert in ARM timers. Could I ask a >>really big >>favor, please? When I read the SBSA (section 5.2, specifically), that >>implies >>to me that there are two interrupts: a first interrupt for the timer >>itself set >>to go off after the timeout expires, and a second interrupt that is >>required >>when the timeout expires to force some "executive action". I only see >>one IRQ >>in the patch; what am I missing? > > The sbsa watchdog has two signals, WS0 and WS1, or as some have now > renamed them, > the bark and bite. At a kernel level the first is going to come in as an > interrupt, > and second will be a essentially a reset.This gives you two chances at > recovery. One > reason for having this second chance is to allow a debug agent to step in > an gather > crash information. > > HTH > > Charles > >> >>Thanks. >> >>> [v4] >>> Removed COMPILE_TEST >>> pm_status is now bool >>> removed some #includes >>> use do_div instead >>> display arch version if unsupported >>> remove watchdog_set_drvdata >>> >>> drivers/watchdog/Kconfig | 9 ++ >>> drivers/watchdog/Makefile | 1 + >>> drivers/watchdog/arm_sbsa_wdt.c | 295 >>>++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 305 insertions(+) >>> create mode 100644 drivers/watchdog/arm_sbsa_wdt.c >>> >>> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig >>> index e5e7c55..7720190 100644 >>> --- a/drivers/watchdog/Kconfig >>> +++ b/drivers/watchdog/Kconfig >>> @@ -514,6 +514,15 @@ config MEDIATEK_WATCHDOG >>> To compile this driver as a module, choose M here: the >>> module will be called mtk_wdt. >>> >>> +config ARM_SBSA_WDT >>> + tristate "ARM Server Base System Architecture watchdog" >>> + depends on ARM64 >>> + depends on ARM_ARCH_TIMER >>> + select WATCHDOG_CORE >>> + help >>> + Say Y here to include watchdog timer support for ARM Server Base >>> + System Architecture (SBSA) systems. >>> + >>> # AVR32 Architecture >>> >>> config AT32AP700X_WDT >>> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile >>> index 5c19294..063ab8c 100644 >>> --- a/drivers/watchdog/Makefile >>> +++ b/drivers/watchdog/Makefile >>> @@ -64,6 +64,7 @@ obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o >>> obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o >>> obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o >>> obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o >>> +obj-$(CONFIG_ARM_SBSA_WDT) += arm_sbsa_wdt.o >>> >>> # AVR32 Architecture >>> obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o >>> diff --git a/drivers/watchdog/arm_sbsa_wdt.c >>>b/drivers/watchdog/arm_sbsa_wdt.c >>> new file mode 100644 >>> index 0000000..12ed520e >>> --- /dev/null >>> +++ b/drivers/watchdog/arm_sbsa_wdt.c >>> @@ -0,0 +1,295 @@ >>> +/* >>> + * Watchdog driver for SBSA-compliant watchdog timers >>> + * >>> + * Copyright (c) 2015, The Linux Foundation. All rights reserved. >>> + * >>> + * This program is free software; you can redistribute it and/or modify >>> + * it under the terms of the GNU General Public License version 2 and >>> + * only version 2 as published by the Free Software Foundation. >>> + * >>> + * This program is distributed in the hope that it will be useful, >>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>> + * GNU General Public License for more details. >>> + * >>> + * ARM Server Base System Architecture watchdog driver. >>> + * >>> + * Register descriptions are taken from the ARM Server Base System >>> + * Architecture document (ARM-DEN-0029) >>> + */ >>> + >>> +#define pr_fmt(fmt) "sbsa-gwdt: " fmt >>> + >>> +#include <linux/module.h> >>> +#include <linux/watchdog.h> >>> +#include <linux/platform_device.h> >>> +#include <linux/of.h> >>> +#include <linux/device.h> >>> +#include <linux/io.h> >>> +#include <linux/interrupt.h> >>> +#include <linux/reboot.h> >>> + >>> +#include <asm/arch_timer.h> >>> + >>> +/* Watchdog Interface Identification Registers */ >>> +struct arm_sbsa_watchdog_ident { >>> + __le32 w_iidr; /* Watchdog Interface Identification Register */ >>> + uint8_t res2[0xFE8 - 0xFD0]; >>> + __le32 w_pidr2; /* Peripheral ID2 Register */ >>> +}; >>> + >>> +/* Watchdog Refresh Frame */ >>> +struct arm_sbsa_watchdog_refresh { >>> + __le32 wrr; /* Watchdog Refresh Register */ >>> + uint8_t res1[0xFCC - 0x004]; >>> + struct arm_sbsa_watchdog_ident ident; >>> +}; >>> + >>> +/* Watchdog Control Frame */ >>> +struct arm_sbsa_watchdog_control { >>> + __le32 wcs; >>> + __le32 res1; >>> + __le32 wor; >>> + __le32 res2; >>> + __le64 wcv; >>> + uint8_t res3[0xFCC - 0x018]; >>> + struct arm_sbsa_watchdog_ident ident; >>> +}; >>> + >>> +struct arm_sbsa_watchdog_data { >>> + struct watchdog_device wdev; >>> + bool pm_status; >>> + struct arm_sbsa_watchdog_refresh __iomem *refresh; >>> + struct arm_sbsa_watchdog_control __iomem *control; >>> +}; >>> + >>> +static int arm_sbsa_wdt_start(struct watchdog_device *wdev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = >>> + container_of(wdev, struct arm_sbsa_watchdog_data, wdev); >>> + >>> + /* Writing to the control register will also reset the counter */ >>> + writel(1, &data->control->wcs); >>> + >>> + return 0; >>> +} >>> + >>> +static int arm_sbsa_wdt_stop(struct watchdog_device *wdev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = >>> + container_of(wdev, struct arm_sbsa_watchdog_data, wdev); >>> + >>> + writel(0, &data->control->wcs); >>> + >>> + return 0; >>> +} >>> + >>> +static int arm_sbsa_wdt_set_timeout(struct watchdog_device *wdev, >>> + unsigned int timeout) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = >>> + container_of(wdev, struct arm_sbsa_watchdog_data, wdev); >>> + >>> + wdev->timeout = timeout; >>> + writel(arch_timer_get_cntfrq() * wdev->timeout, &data->control->wor); >>> + >>> + return 0; >>> +} >>> + >>> +static int arm_sbsa_wdt_ping(struct watchdog_device *wdev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = >>> + container_of(wdev, struct arm_sbsa_watchdog_data, wdev); >>> + >>> + writel(1, &data->refresh->wrr); >>> + >>> + return 0; >>> +} >>> + >>> +static unsigned int arm_sbsa_wdt_status(struct watchdog_device *wdev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = >>> + container_of(wdev, struct arm_sbsa_watchdog_data, wdev); >>> + >>> + return (readl(&data->control->wcs) & 1) << WDOG_ACTIVE; >>> +} >>> + >>> +static unsigned int arm_sbsa_wdt_timeleft(struct watchdog_device *wdev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = >>> + container_of(wdev, struct arm_sbsa_watchdog_data, wdev); >>> + uint64_t diff = readq(&data->control->wcv) - >>>arch_counter_get_cntvct(); >>> + >>> + do_div(diff, arch_timer_get_cntfrq()); >>> + >>> + return diff; >>> +} >>> + >>> +static irqreturn_t arm_sbsa_wdt_interrupt(int irq, void *p) >>> +{ >>> + /* >>> + * The WS0 interrupt occurs after the first timeout, so we attempt >>> + * a manual reboot. If this doesn't work, the WS1 timeout will >>> + * cause a hardware reset. >>> + */ >>> + pr_crit("Initiating system reboot\n"); >>> + emergency_restart(); >>> + >>> + return IRQ_HANDLED; >>> +} >>> + >>> +/* >>> + * Disable watchdog if it is active during suspend >>> + */ >>> +static int __maybe_unused arm_sbsa_wdt_suspend(struct device *dev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = dev_get_drvdata(dev); >>> + >>> + data->pm_status = !!(readl(&data->control->wcs) & 1); >>> + >>> + if (data->pm_status) >>> + writel(0, &data->control->wcs); >>> + >>> + return 0; >>> +} >>> + >>> +/* >>> + * Enable watchdog and configure it if necessary >>> + */ >>> +static int __maybe_unused arm_sbsa_wdt_resume(struct device *dev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = dev_get_drvdata(dev); >>> + >>> + if (data->pm_status) >>> + writel(1, &data->control->wcs); >>> + >>> + return 0; >>> +} >>> + >>> +static const struct dev_pm_ops arm_sbsa_wdt_pm_ops = { >>> + SET_SYSTEM_SLEEP_PM_OPS(arm_sbsa_wdt_suspend, arm_sbsa_wdt_resume) >>> +}; >>> + >>> +static struct watchdog_info arm_sbsa_wdt_info = { >>> + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, >>> + .identity = "ARM SBSA watchdog", >>> +}; >>> + >>> +static struct watchdog_ops arm_sbsa_wdt_ops = { >>> + .owner = THIS_MODULE, >>> + .start = arm_sbsa_wdt_start, >>> + .stop = arm_sbsa_wdt_stop, >>> + .ping = arm_sbsa_wdt_ping, >>> + .set_timeout = arm_sbsa_wdt_set_timeout, >>> + .status = arm_sbsa_wdt_status, >>> + .get_timeleft = arm_sbsa_wdt_timeleft, >>> +}; >>> + >>> +static int __init arm_sbsa_wdt_probe(struct platform_device *pdev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data; >>> + struct resource *res; >>> + uint32_t iidr; >>> + unsigned int arch; >>> + int irq, ret; >>> + >>> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); >>> + if (!data) >>> + return -ENOMEM; >>> + >>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control"); >>> + data->control = devm_ioremap_resource(&pdev->dev, res); >>> + if (IS_ERR(data->control)) >>> + return PTR_ERR(data->control); >>> + >>> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "refresh"); >>> + data->refresh = devm_ioremap_resource(&pdev->dev, res); >>> + if (IS_ERR(data->refresh)) >>> + return PTR_ERR(data->refresh); >>> + >>> + /* We only support architecture version 0 */ >>> + iidr = readl(&data->control->ident.w_iidr); >>> + arch = (iidr >> 16) & 0xf; >>> + if (arch != 0) { >>> + dev_err(&pdev->dev, >>> + "architecture version %u is not supported\n", arch); >>> + return -ENODEV; >>> + } >>> + >>> + irq = platform_get_irq_byname(pdev, "ws0"); >>> + if (irq < 0) { >>> + dev_err(&pdev->dev, "could not get interrupt\n"); >>> + return irq; >>> + } >>> + >>> + ret = devm_request_irq(&pdev->dev, irq, arm_sbsa_wdt_interrupt, >>> + 0, pdev->name, NULL); >>> + if (ret < 0) { >>> + dev_err(&pdev->dev, "could not request irq %i (ret=%i)\n", >>> + irq, ret); >>> + return ret; >>> + } >>> + >>> + data->wdev.info = &arm_sbsa_wdt_info; >>> + data->wdev.ops = &arm_sbsa_wdt_ops; >>> + data->wdev.min_timeout = 1; >>> + data->wdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; >>> + >>> + /* Calculate the maximum timeout in seconds that we can support */ >>> + data->wdev.max_timeout = U32_MAX / arch_timer_get_cntfrq(); >>> + >>> + /* >>> + * Bits [15:12] are an implementation-defined revision number >>> + * for the component. >>> + */ >>> + arm_sbsa_wdt_info.firmware_version = (iidr >> 12) & 0xf; >>> + >>> + ret = watchdog_register_device(&data->wdev); >>> + if (ret < 0) { >>> + dev_err(&pdev->dev, >>> + "could not register watchdog device (ret=%i)\n", ret); >>> + return ret; >>> + } >>> + >>> + dev_dbg(&pdev->dev, "implementer code is %03x\n", >>> + (iidr & 0xf00) >> 1 | (iidr & 0x7f)); >>> + dev_info(&pdev->dev, "maximum timeout is %u seconds\n", >>> + data->wdev.max_timeout); >>> + >>> + platform_set_drvdata(pdev, data); >>> + >>> + return 0; >>> +} >>> + >>> +static int __exit arm_sbsa_wdt_remove(struct platform_device *pdev) >>> +{ >>> + struct arm_sbsa_watchdog_data *data = platform_get_drvdata(pdev); >>> + >>> + watchdog_unregister_device(&data->wdev); >>> + >>> + return 0; >>> +} >>> + >>> +#if IS_ENABLED(CONFIG_OF) >>> +static const struct of_device_id arm_sbsa_wdt_of_match[] = { >>> + { .compatible = "arm,sbsa-gwdt" }, >>> + {}, >>> +}; >>> +MODULE_DEVICE_TABLE(of, arm_sbsa_wdt_of_match); >>> +#endif >>> + >>> +static struct platform_driver arm_sbsa_wdt_driver = { >>> + .driver = { >>> + .name = "sbsa-gwdt", >>> + .owner = THIS_MODULE, >>> + .pm = &arm_sbsa_wdt_pm_ops, >>> + .of_match_table = of_match_ptr(arm_sbsa_wdt_of_match), >>> + }, >>> + .probe = arm_sbsa_wdt_probe, >>> + .remove = __exit_p(arm_sbsa_wdt_remove), >>> +}; >>> + >>> +module_platform_driver(arm_sbsa_wdt_driver); >>> + >>> +MODULE_DESCRIPTION("ARM Server Base System Architecture Watchdog >>>Driver"); >>> +MODULE_LICENSE("GPL v2"); >>> >> >> >>-- >>ciao, >>al >>----------------------------------- >>Al Stone >>Software Engineer >>Linaro Enterprise Group >>al.stone@xxxxxxxxxx >>----------------------------------- >>_______________________________________________ >>Linaro-acpi mailing list >>Linaro-acpi@xxxxxxxxxxxxxxxx >>https://lists.linaro.org/mailman/listinfo/linaro-acpi > > -- Best regards, Fu Wei Software Engineer Red Hat Software (Beijing) Co.,Ltd.Shanghai Branch Ph: +86 21 61221326(direct) Ph: +86 186 2020 4684 (mobile) Room 1512, Regus One Corporate Avenue,Level 15, One Corporate Avenue,222 Hubin Road,Huangpu District, Shanghai,China 200021 -- To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html