Hi

On 5/26/15, 6:11 PM, "Al Stone" <[email protected]> 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 <[email protected]>
>> ---
>
>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
>[email protected]
>-----------------------------------
>_______________________________________________
>Linaro-acpi mailing list
>[email protected]
>https://lists.linaro.org/mailman/listinfo/linaro-acpi


--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to