Re: [Linaro-acpi] [PATCH] [v4] watchdog: introduce the ARM64 SBSA watchdog driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


--
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




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux