From 0f0dbd9b36bbca6ffc0852d7859edc0ac8f11727 Mon Sep 17 00:00:00 2001 From: Shyam Saini Date: Tue, 7 Apr 2020 03:20:08 +0530 Subject: [PATCH 01/14] watchdog: ts72xx_wdt: fix build error If TS72XX_WATCHDOG is y and WATCHDOG_CORE is not enabled or its m, then building fails: drivers/watchdog/ts72xx_wdt.o: in function `ts72xx_wdt_probe': ts72xx_wdt.c:(.text+0x14c): undefined reference to \ `watchdog_init_timeout' ts72xx_wdt.c:(.text+0x15c): undefined reference to \ `devm_watchdog_register_device' Select WATCHDOG_CORE to fix this. Signed-off-by: Shyam Saini Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200406215008.30468-1-shyam.saini@savoirfairelinux.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 0663c604bd64..a0399a5b2a30 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -678,6 +678,7 @@ config TS4800_WATCHDOG config TS72XX_WATCHDOG tristate "TS-72XX SBC Watchdog" depends on MACH_TS72XX || COMPILE_TEST + select WATCHDOG_CORE help Technologic Systems TS-7200, TS-7250 and TS-7260 boards have watchdog timer implemented in a external CPLD chip. Say Y here From e56d48e92b1017b6a8dbe64923a889283733fd96 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 12 Apr 2020 20:01:22 -0300 Subject: [PATCH 02/14] watchdog: imx_sc_wdt: Fix reboot on crash Currently when running the samples/watchdog/watchdog-simple.c application and forcing a kernel crash by doing: # ./watchdog-simple & # echo c > /proc/sysrq-trigger The system does not reboot as expected. Fix it by calling imx_sc_wdt_set_timeout() to configure the i.MX8QXP watchdog with a proper timeout. Cc: Fixes: 986857acbc9a ("watchdog: imx_sc: Add i.MX system controller watchdog support") Reported-by: Breno Lima Signed-off-by: Fabio Estevam Reviewed-by: Guenter Roeck Tested-by: Breno Lima Link: https://lore.kernel.org/r/20200412230122.5601-1-festevam@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imx_sc_wdt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/watchdog/imx_sc_wdt.c b/drivers/watchdog/imx_sc_wdt.c index 60a32469f7de..e9ee22a7cb45 100644 --- a/drivers/watchdog/imx_sc_wdt.c +++ b/drivers/watchdog/imx_sc_wdt.c @@ -175,6 +175,11 @@ static int imx_sc_wdt_probe(struct platform_device *pdev) wdog->timeout = DEFAULT_TIMEOUT; watchdog_init_timeout(wdog, 0, dev); + + ret = imx_sc_wdt_set_timeout(wdog, wdog->timeout); + if (ret) + return ret; + watchdog_stop_on_reboot(wdog); watchdog_stop_on_unregister(wdog); From f249eef9e66e46065a42a0c164ecc3a40f52102a Mon Sep 17 00:00:00 2001 From: Bumsik Kim Date: Fri, 3 Apr 2020 12:15:07 +0900 Subject: [PATCH 03/14] watchdog: clarify that stop() is optional The commit d0684c8a9354 ("watchdog: Make stop function optional") made stop function not mandatory, but the comments and the doc weren't reflected. Fix it to clarify. Signed-off-by: Bumsik Kim Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200403031507.63487-1-k.bumsik@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/watchdog/convert_drivers_to_kernel_api.rst | 2 +- Documentation/watchdog/watchdog-kernel-api.rst | 2 +- include/linux/watchdog.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/watchdog/convert_drivers_to_kernel_api.rst b/Documentation/watchdog/convert_drivers_to_kernel_api.rst index dd934cc08e40..51b999b5551a 100644 --- a/Documentation/watchdog/convert_drivers_to_kernel_api.rst +++ b/Documentation/watchdog/convert_drivers_to_kernel_api.rst @@ -115,7 +115,7 @@ Add the watchdog operations --------------------------- All possible callbacks are defined in 'struct watchdog_ops'. You can find it -explained in 'watchdog-kernel-api.txt' in this directory. start(), stop() and +explained in 'watchdog-kernel-api.txt' in this directory. start() and owner must be set, the rest are optional. You will easily find corresponding functions in the old driver. Note that you will now get a pointer to the watchdog_device as a parameter to these functions, so you probably have to diff --git a/Documentation/watchdog/watchdog-kernel-api.rst b/Documentation/watchdog/watchdog-kernel-api.rst index 864edbe932c1..068a55ee0d4a 100644 --- a/Documentation/watchdog/watchdog-kernel-api.rst +++ b/Documentation/watchdog/watchdog-kernel-api.rst @@ -123,8 +123,8 @@ The list of watchdog operations is defined as:: struct module *owner; /* mandatory operations */ int (*start)(struct watchdog_device *); - int (*stop)(struct watchdog_device *); /* optional operations */ + int (*stop)(struct watchdog_device *); int (*ping)(struct watchdog_device *); unsigned int (*status)(struct watchdog_device *); int (*set_timeout)(struct watchdog_device *, unsigned int); diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 417d9f37077a..1464ce6ffa31 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -37,15 +37,15 @@ struct watchdog_governor; * * The watchdog_ops structure contains a list of low-level operations * that control a watchdog device. It also contains the module that owns - * these operations. The start and stop function are mandatory, all other + * these operations. The start function is mandatory, all other * functions are optional. */ struct watchdog_ops { struct module *owner; /* mandatory operations */ int (*start)(struct watchdog_device *); - int (*stop)(struct watchdog_device *); /* optional operations */ + int (*stop)(struct watchdog_device *); int (*ping)(struct watchdog_device *); unsigned int (*status)(struct watchdog_device *); int (*set_timeout)(struct watchdog_device *, unsigned int); From e8799ce85992defa341613c5c6f083fa412266f3 Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Fri, 3 Apr 2020 15:07:26 +0200 Subject: [PATCH 04/14] watchdog: da9062: Initialize timeout during probe During probe try to set the timeout from device tree and fall back to either the pre-configured timeout set by e.g. the bootloader in case the watchdog is already running or the default value. If the watchdog is already running make sure to update the timeout and tell the framework about the running state to make sure the watchdog is handled correctly until user space takes over. Updating the timeout also removes the need for an additional manual ping so we can remove that as well. Signed-off-by: Stefan Riedmueller Reviewed-by: Adam Thomson Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200403130728.39260-1-s.riedmueller@phytec.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/da9062_wdt.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index 0ad15d55071c..10b37dd65bed 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -35,6 +35,15 @@ struct da9062_watchdog { bool use_sw_pm; }; +static unsigned int da9062_wdt_read_timeout(struct da9062_watchdog *wdt) +{ + unsigned int val; + + regmap_read(wdt->hw->regmap, DA9062AA_CONTROL_D, &val); + + return wdt_timeout[val & DA9062AA_TWDSCALE_MASK]; +} + static unsigned int da9062_wdt_timeout_to_sel(unsigned int secs) { unsigned int i; @@ -183,7 +192,7 @@ MODULE_DEVICE_TABLE(of, da9062_compatible_id_table); static int da9062_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - int ret; + unsigned int timeout; struct da9062 *chip; struct da9062_watchdog *wdt; @@ -213,11 +222,19 @@ static int da9062_wdt_probe(struct platform_device *pdev) watchdog_set_drvdata(&wdt->wdtdev, wdt); dev_set_drvdata(dev, &wdt->wdtdev); - ret = devm_watchdog_register_device(dev, &wdt->wdtdev); - if (ret < 0) - return ret; + timeout = da9062_wdt_read_timeout(wdt); + if (timeout) + wdt->wdtdev.timeout = timeout; - return da9062_wdt_ping(&wdt->wdtdev); + /* Set timeout from DT value if available */ + watchdog_init_timeout(&wdt->wdtdev, 0, dev); + + if (timeout) { + da9062_wdt_set_timeout(&wdt->wdtdev, wdt->wdtdev.timeout); + set_bit(WDOG_HW_RUNNING, &wdt->wdtdev.status); + } + + return devm_watchdog_register_device(dev, &wdt->wdtdev); } static int __maybe_unused da9062_wdt_suspend(struct device *dev) From c4718308d77782bb438287f67a45ed9e9df712cf Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Fri, 3 Apr 2020 15:07:27 +0200 Subject: [PATCH 05/14] watchdog: da9063: Make use of pre-configured timeout during probe The watchdog might already be running during boot with a timeout set by e.g. the bootloader. Make use of this pre-configured timeout instead of falling back to the default timeout if no device tree value is given. Signed-off-by: Stefan Riedmueller Reviewed-by: Adam Thomson Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200403130728.39260-2-s.riedmueller@phytec.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/da9063_wdt.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 3d65e92a4e3f..423584252606 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -46,15 +46,16 @@ static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs) } /* - * Return 0 if watchdog is disabled, else non zero. + * Read the currently active timeout. + * Zero means the watchdog is disabled. */ -static unsigned int da9063_wdt_is_running(struct da9063 *da9063) +static unsigned int da9063_wdt_read_timeout(struct da9063 *da9063) { unsigned int val; regmap_read(da9063->regmap, DA9063_REG_CONTROL_D, &val); - return val & DA9063_TWDSCALE_MASK; + return wdt_timeout[val & DA9063_TWDSCALE_MASK]; } static int da9063_wdt_disable_timer(struct da9063 *da9063) @@ -191,6 +192,7 @@ static int da9063_wdt_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct da9063 *da9063; struct watchdog_device *wdd; + unsigned int timeout; if (!dev->parent) return -EINVAL; @@ -214,13 +216,19 @@ static int da9063_wdt_probe(struct platform_device *pdev) watchdog_set_restart_priority(wdd, 128); watchdog_set_drvdata(wdd, da9063); - /* Set default timeout, maybe override it with DT value, scale it */ wdd->timeout = DA9063_WDG_TIMEOUT; + + /* Use pre-configured timeout if watchdog is already running. */ + timeout = da9063_wdt_read_timeout(da9063); + if (timeout) + wdd->timeout = timeout; + + /* Set timeout, maybe override it with DT value, scale it */ watchdog_init_timeout(wdd, 0, dev); da9063_wdt_set_timeout(wdd, wdd->timeout); - /* Change the timeout to the default value if the watchdog is running */ - if (da9063_wdt_is_running(da9063)) { + /* Update timeout if the watchdog is already running. */ + if (timeout) { da9063_wdt_update_timeout(da9063, wdd->timeout); set_bit(WDOG_HW_RUNNING, &wdd->status); } From a0948ddba65f4f6d3cfb5e2b84685485d0452966 Mon Sep 17 00:00:00 2001 From: Stefan Riedmueller Date: Fri, 3 Apr 2020 15:07:28 +0200 Subject: [PATCH 06/14] watchdog: da9062: No need to ping manually before setting timeout There is actually no need to ping the watchdog before disabling it during timeout change. Disabling the watchdog already takes care of resetting the counter. This fixes an issue during boot when the userspace watchdog handler takes over and the watchdog is already running. Opening the watchdog in this case leads to the first ping and directly after that without the required heartbeat delay a second ping issued by the set_timeout call. Due to the missing delay this resulted in a reset. Signed-off-by: Stefan Riedmueller Reviewed-by: Guenter Roeck Reviewed-by: Adam Thomson Link: https://lore.kernel.org/r/20200403130728.39260-3-s.riedmueller@phytec.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/da9062_wdt.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index 10b37dd65bed..706fb09c2f24 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -67,11 +67,6 @@ static int da9062_wdt_update_timeout_register(struct da9062_watchdog *wdt, unsigned int regval) { struct da9062 *chip = wdt->hw; - int ret; - - ret = da9062_reset_watchdog_timer(wdt); - if (ret) - return ret; regmap_update_bits(chip->regmap, DA9062AA_CONTROL_D, From b30c1a464c29baf646a5726d90ea3537e775ac85 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 28 Apr 2020 23:29:11 +0200 Subject: [PATCH 07/14] watchdog: iTCO: fix link error When the MFD driver is a loadable module, the watchdog driver fails to get linked into the kernel: drivers/watchdog/iTCO_wdt.o: In function `update_no_reboot_bit_pmc': iTCO_wdt.c:(.text+0x54f): undefined reference to `intel_pmc_gcr_update' The code is written to support operation without the MFD driver, so add a Kconfig dependency that allows this, while disallowing the watchdog to be built-in when the MFD driver is a module. Fixes: 25f1ca31e230 ("platform/x86: intel_pmc_ipc: Convert to MFD") Signed-off-by: Arnd Bergmann Acked-by: Guenter Roeck Reviewed-by: Mika Westerberg Link: https://lore.kernel.org/r/20200428212959.2993304-1-arnd@arndb.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index a0399a5b2a30..b3ab5a4bc71a 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1218,6 +1218,7 @@ config ITCO_WDT depends on (X86 || IA64) && PCI select WATCHDOG_CORE depends on I2C || I2C=n + depends on MFD_INTEL_PMC_BXT || !MFD_INTEL_PMC_BXT select LPC_ICH if !EXPERT select I2C_I801 if !EXPERT && I2C ---help--- From 62c35b44f294d35f3e5d0e76c1cde75ab189ef28 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 2 May 2020 16:26:53 +0200 Subject: [PATCH 08/14] watchdog: imx2_wdt: update contact email The 'pengutronix' address is defunct for years. Use the proper contact address. Signed-off-by: Wolfram Sang Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200502142653.19144-1-wsa@kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imx2_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 1fe472f56cb3..b84f80f7d342 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -2,7 +2,7 @@ /* * Watchdog driver for IMX2 and later processors * - * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. + * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. * Copyright (C) 2014 Freescale Semiconductor, Inc. * * some parts adapted by similar drivers from Darius Augulis and Vladimir From 5c24a28b4eb842ad1256496be6ae01bab15f1dcb Mon Sep 17 00:00:00 2001 From: Evan Benn Date: Tue, 5 May 2020 13:13:30 +1000 Subject: [PATCH 09/14] dt-bindings: watchdog: Add ARM smc wdt for mt8173 watchdog This watchdog can be used on ARM systems with a Secure Monitor firmware to forward watchdog operations to firmware via a Secure Monitor Call. Signed-off-by: Evan Benn Reviewed-by: Rob Herring Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200505131242.v6.1.Id96574f1f52479d7a2f3b866b8a0552ab8c03d7f@changeid Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../bindings/watchdog/arm-smc-wdt.yaml | 37 +++++++++++++++++++ MAINTAINERS | 6 +++ 2 files changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml diff --git a/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml b/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml new file mode 100644 index 000000000000..bec651541e0c --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/arm-smc-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Secure Monitor Call based watchdog + +allOf: + - $ref: "watchdog.yaml#" + +maintainers: + - Julius Werner + +properties: + compatible: + enum: + - arm,smc-wdt + arm,smc-id: + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + description: | + The ATF smc function id used by the firmware. + Defaults to 0x82003D06 if unset. + +required: + - compatible + +examples: + - | + watchdog { + compatible = "arm,smc-wdt"; + arm,smc-id = <0x82003D06>; + timeout-sec = <15>; + }; + +... diff --git a/MAINTAINERS b/MAINTAINERS index 50659d76976b..7c062ef0ebb2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1456,6 +1456,12 @@ S: Maintained F: Documentation/devicetree/bindings/interrupt-controller/arm,vic.txt F: drivers/irqchip/irq-vic.c +ARM SMC WATCHDOG DRIVER +M: Julius Werner +R: Evan Benn +S: Maintained +F: devicetree/bindings/watchdog/arm-smc-wdt.yaml + ARM SMMU DRIVERS M: Will Deacon R: Robin Murphy From 72a9e7fea5866fc471fda78f05f166595c8c6ba6 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Tue, 5 May 2020 13:13:31 +1000 Subject: [PATCH 10/14] watchdog: Add new arm_smc_wdt watchdog driver This patch adds a watchdog driver that can be used on ARM systems with the appropriate watchdog implemented in Secure Monitor firmware. The driver communicates with firmware via a Secure Monitor Call. This may be useful for platforms using TrustZone that want the Secure Monitor firmware to have the final control over the watchdog. This is implemented on mt8173 chromebook devices oak, elm and hana in arm trusted firmware file plat/mediatek/mt8173/drivers/wdt/wdt.c. Signed-off-by: Julius Werner Signed-off-by: Evan Benn Reviewed-by: Julius Werner Tested-by: Xingyu Chen Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200505131242.v6.2.Ia92bb4d4ce84bcefeba1d00aaa1c1e919b6164ef@changeid Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- MAINTAINERS | 1 + arch/arm64/configs/defconfig | 1 + drivers/watchdog/Kconfig | 13 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/arm_smc_wdt.c | 188 +++++++++++++++++++++++++++++++++ 5 files changed, 204 insertions(+) create mode 100644 drivers/watchdog/arm_smc_wdt.c diff --git a/MAINTAINERS b/MAINTAINERS index 7c062ef0ebb2..440968823b8e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1461,6 +1461,7 @@ M: Julius Werner R: Evan Benn S: Maintained F: devicetree/bindings/watchdog/arm-smc-wdt.yaml +F: drivers/watchdog/arm_smc_wdt.c ARM SMMU DRIVERS M: Will Deacon diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 03d0189f7d68..71d9ca727eee 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -513,6 +513,7 @@ CONFIG_UNIPHIER_THERMAL=y CONFIG_WATCHDOG=y CONFIG_ARM_SP805_WATCHDOG=y CONFIG_ARM_SBSA_WATCHDOG=y +CONFIG_ARM_SMC_WATCHDOG=y CONFIG_S3C2410_WATCHDOG=y CONFIG_DW_WATCHDOG=y CONFIG_SUNXI_WATCHDOG=m diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b3ab5a4bc71a..55b910c453da 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -868,6 +868,19 @@ config DIGICOLOR_WATCHDOG To compile this driver as a module, choose M here: the module will be called digicolor_wdt. +config ARM_SMC_WATCHDOG + tristate "ARM Secure Monitor Call based watchdog support" + depends on ARM || ARM64 + depends on OF + depends on HAVE_ARM_SMCCC + select WATCHDOG_CORE + help + Say Y here to include support for a watchdog timer + implemented by the EL3 Secure Monitor on ARM platforms. + Requires firmware support. + To compile this driver as a module, choose M here: the + module will be called arm_smc_wdt. + config LPC18XX_WATCHDOG tristate "LPC18xx/43xx Watchdog" depends on ARCH_LPC18XX || COMPILE_TEST diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 6de2e4ceef19..97bed1d3d97c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -94,6 +94,7 @@ obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o obj-$(CONFIG_RTD119X_WATCHDOG) += rtd119x_wdt.o obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o +obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/watchdog/arm_smc_wdt.c b/drivers/watchdog/arm_smc_wdt.c new file mode 100644 index 000000000000..8f3d0c3a005f --- /dev/null +++ b/drivers/watchdog/arm_smc_wdt.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ARM Secure Monitor Call watchdog driver + * + * Copyright 2020 Google LLC. + * Julius Werner + * Based on mtk_wdt.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "arm_smc_wdt" +#define DRV_VERSION "1.0" + +enum smcwd_call { + SMCWD_INIT = 0, + SMCWD_SET_TIMEOUT = 1, + SMCWD_ENABLE = 2, + SMCWD_PET = 3, + SMCWD_GET_TIMELEFT = 4, +}; + +static bool nowayout = WATCHDOG_NOWAYOUT; +static unsigned int timeout; + +static int smcwd_call(struct watchdog_device *wdd, enum smcwd_call call, + unsigned long arg, struct arm_smccc_res *res) +{ + struct arm_smccc_res local_res; + + if (!res) + res = &local_res; + + arm_smccc_smc((u32)(uintptr_t)watchdog_get_drvdata(wdd), call, arg, 0, + 0, 0, 0, 0, res); + + if (res->a0 == PSCI_RET_NOT_SUPPORTED) + return -ENODEV; + if (res->a0 == PSCI_RET_INVALID_PARAMS) + return -EINVAL; + if (res->a0 != PSCI_RET_SUCCESS) + return -EIO; + return 0; +} + +static int smcwd_ping(struct watchdog_device *wdd) +{ + return smcwd_call(wdd, SMCWD_PET, 0, NULL); +} + +static unsigned int smcwd_get_timeleft(struct watchdog_device *wdd) +{ + struct arm_smccc_res res; + + smcwd_call(wdd, SMCWD_GET_TIMELEFT, 0, &res); + if (res.a0) + return 0; + return res.a1; +} + +static int smcwd_set_timeout(struct watchdog_device *wdd, unsigned int timeout) +{ + int res; + + res = smcwd_call(wdd, SMCWD_SET_TIMEOUT, timeout, NULL); + if (!res) + wdd->timeout = timeout; + return res; +} + +static int smcwd_stop(struct watchdog_device *wdd) +{ + return smcwd_call(wdd, SMCWD_ENABLE, 0, NULL); +} + +static int smcwd_start(struct watchdog_device *wdd) +{ + return smcwd_call(wdd, SMCWD_ENABLE, 1, NULL); +} + +static const struct watchdog_info smcwd_info = { + .identity = DRV_NAME, + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +static const struct watchdog_ops smcwd_ops = { + .start = smcwd_start, + .stop = smcwd_stop, + .ping = smcwd_ping, + .set_timeout = smcwd_set_timeout, +}; + +static const struct watchdog_ops smcwd_timeleft_ops = { + .start = smcwd_start, + .stop = smcwd_stop, + .ping = smcwd_ping, + .set_timeout = smcwd_set_timeout, + .get_timeleft = smcwd_get_timeleft, +}; + +static int smcwd_probe(struct platform_device *pdev) +{ + struct watchdog_device *wdd; + int err; + struct arm_smccc_res res; + u32 smc_func_id; + + wdd = devm_kzalloc(&pdev->dev, sizeof(*wdd), GFP_KERNEL); + if (!wdd) + return -ENOMEM; + platform_set_drvdata(pdev, wdd); + + if (of_property_read_u32(pdev->dev.of_node, "arm,smc-id", + &smc_func_id)) + smc_func_id = 0x82003D06; + watchdog_set_drvdata(wdd, (void *)(uintptr_t)smc_func_id); + + err = smcwd_call(wdd, SMCWD_INIT, 0, &res); + if (err < 0) + return err; + + wdd->info = &smcwd_info; + /* get_timeleft is optional */ + if (smcwd_call(wdd, SMCWD_GET_TIMELEFT, 0, NULL)) + wdd->ops = &smcwd_ops; + else + wdd->ops = &smcwd_timeleft_ops; + wdd->timeout = res.a2; + wdd->max_timeout = res.a2; + wdd->min_timeout = res.a1; + wdd->parent = &pdev->dev; + + watchdog_stop_on_reboot(wdd); + watchdog_stop_on_unregister(wdd); + watchdog_set_nowayout(wdd, nowayout); + watchdog_init_timeout(wdd, timeout, &pdev->dev); + err = smcwd_set_timeout(wdd, wdd->timeout); + if (err) + return err; + + err = devm_watchdog_register_device(&pdev->dev, wdd); + if (err) + return err; + + dev_info(&pdev->dev, + "Watchdog registered (timeout=%d sec, nowayout=%d)\n", + wdd->timeout, nowayout); + + return 0; +} + +static const struct of_device_id smcwd_dt_ids[] = { + { .compatible = "arm,smc-wdt" }, + {} +}; +MODULE_DEVICE_TABLE(of, smcwd_dt_ids); + +static struct platform_driver smcwd_driver = { + .probe = smcwd_probe, + .driver = { + .name = DRV_NAME, + .of_match_table = smcwd_dt_ids, + }, +}; + +module_platform_driver(smcwd_driver); + +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds"); + +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Julius Werner "); +MODULE_DESCRIPTION("ARM Secure Monitor Call Watchdog Driver"); +MODULE_VERSION(DRV_VERSION); From 5e31896a33c5ad5ad5c533e6bdff6510d136b1ef Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Tue, 28 Apr 2020 14:33:33 +0800 Subject: [PATCH 11/14] watchdog: riowd: remove unneeded semicolon Fix the following coccicheck warning: drivers/watchdog/riowd.c:144:2-3: Unneeded semicolon Signed-off-by: Jason Yan Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200428063333.2743-1-yanaijie@huawei.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/riowd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c index dc3c06a92f93..1b9a6dc8f982 100644 --- a/drivers/watchdog/riowd.c +++ b/drivers/watchdog/riowd.c @@ -141,7 +141,7 @@ static long riowd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) default: return -EINVAL; - }; + } return 0; } From a22573740d93f31c30b57a40b334a1ec6b789f67 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Thu, 21 May 2020 16:01:41 +0800 Subject: [PATCH 12/14] watchdog: Fix runtime PM imbalance on error When watchdog_register_device() returns an error code, a pairing runtime PM usage counter decrement is needed to keep the counter balanced. Signed-off-by: Dinghao Liu Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200521080141.24373-1-dinghao.liu@zju.edu.cn Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/omap_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 9b91882fe3c4..1616f93dfad7 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -273,6 +273,7 @@ static int omap_wdt_probe(struct platform_device *pdev) ret = watchdog_register_device(&wdev->wdog); if (ret) { + pm_runtime_put(wdev->dev); pm_runtime_disable(wdev->dev); return ret; } From ff1ee6fb276c90b1b610978736693abe24f0a897 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Fri, 15 May 2020 16:08:56 +0100 Subject: [PATCH 13/14] dt-bindings: watchdog: renesas,wdt: Document r8a7742 support RZ/G1H (R8A7742) watchdog implementation is compatible with R-Car Gen2, therefore add relevant documentation. Signed-off-by: Lad Prabhakar Reviewed-by: Marian-Cristian Rotariu Reviewed-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/1589555337-5498-17-git-send-email-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/devicetree/bindings/watchdog/renesas,wdt.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/watchdog/renesas,wdt.txt b/Documentation/devicetree/bindings/watchdog/renesas,wdt.txt index 79b3c62f183d..e42fd3019cb7 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/renesas,wdt.txt @@ -5,6 +5,7 @@ Required properties: fallback compatible string when compatible with the generic version. Examples with soctypes are: + - "renesas,r8a7742-wdt" (RZ/G1H) - "renesas,r8a7743-wdt" (RZ/G1M) - "renesas,r8a7744-wdt" (RZ/G1N) - "renesas,r8a7745-wdt" (RZ/G1E) From 072cb8b628d312f5785ffdf324286a0519aed910 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 8 May 2020 21:26:58 +0200 Subject: [PATCH 14/14] watchdog: m54xx: Add missing include A recent cleanup removed the mm.h include from uaccess_no.h in m68k. This breaks the build of the m54xx watchdog driver: drivers/watchdog/m54xx_wdt.c:49:9: error: implicit declaration of function '__raw_readl' Due to magic include chains the inclusion of mm.h in uaccess_no.h pulled in io.h. Include 'linux/io.h' explicitely to fix this. Fixes: 9e860351550b ("m68knommu: Remove mm.h include from uaccess_no.h") Reported-by: kbuild test robot Signed-off-by: Thomas Gleixner Cc: Wim Van Sebroeck Cc: Guenter Roeck Cc: linux-watchdog@vger.kernel.org Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/87blmyjjtf.fsf@nanos.tec.linutronix.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/m54xx_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/m54xx_wdt.c b/drivers/watchdog/m54xx_wdt.c index 22f335e1e164..60ed6252e5f4 100644 --- a/drivers/watchdog/m54xx_wdt.c +++ b/drivers/watchdog/m54xx_wdt.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include