diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-25 10:19:17 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-25 10:19:17 -0700 |
commit | 1f93d2abf488c6a41bdd5e6caf80b559493eea8d (patch) | |
tree | 6c81f37167ee42fed575d48e2fcc6dc92ec1d79f | |
parent | 48dd7cefa010b704eb2532a2883798fd6d703a0e (diff) | |
parent | 540be8b2add1a18a4289b11c1a9b6956eb846630 (diff) |
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck:
- add support for Fintek F81865 Super-IO chip
- add support for watchdogs (RWDT and SWDT) found on RCar Gen3 based
SoCs from Renesas
- octeon: Handle the FROZEN hot plug notifier actions
- f71808e_wdt fixes and cleanups
- some small improvements in code and documentation
* git://www.linux-watchdog.org/linux-watchdog:
MAINTAINERS: Add file patterns for watchdog device tree bindings
Documentation: Add ebc-c384_wdt watchdog-parameters.txt entry
watchdog: shwdt: Use setup_timer()
watchdog: cpwd: Use setup_timer()
arm64: defconfig: enable Renesas Watchdog Timer
watchdog: renesas-wdt: add driver
watchdog: remove error message when unable to allocate watchdog device
watchdog: f71808e_wdt: Fix WDTMOUT_STS register read
watchdog: f71808e_wdt: Fix typo
watchdog: f71808e_wdt: Add F81865 support
watchdog: sp5100_tco: properly check for new register layouts
watchdog: core: Fix circular locking dependency
watchdog: core: fix trivial typo in a comment
watchdog: hpwdt: Adjust documentation to match latest kernel module parameters.
watchdog: imx2_wdt: add external reset support via dt prop
watchdog: octeon: Handle the FROZEN hot plug notifier actions.
watchdog: qcom: Report reboot reason
-rw-r--r-- | Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt | 4 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/watchdog/renesas-wdt.txt | 25 | ||||
-rw-r--r-- | Documentation/watchdog/hpwdt.txt | 57 | ||||
-rw-r--r-- | Documentation/watchdog/watchdog-parameters.txt | 4 | ||||
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | arch/arm64/configs/defconfig | 2 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 8 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/cpwd.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/f71808e_wdt.c | 30 | ||||
-rw-r--r-- | drivers/watchdog/imx2_wdt.c | 19 | ||||
-rw-r--r-- | drivers/watchdog/jz4740_wdt.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/octeon-wdt-main.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/qcom-wdt.c | 7 | ||||
-rw-r--r-- | drivers/watchdog/renesas_wdt.c | 213 | ||||
-rw-r--r-- | drivers/watchdog/shwdt.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/sp5100_tco.c | 15 | ||||
-rw-r--r-- | drivers/watchdog/watchdog_core.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 1 |
19 files changed, 349 insertions, 54 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt index 8dab6fd024aa..107280ef0025 100644 --- a/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt @@ -5,10 +5,12 @@ Required properties: - reg : Should contain WDT registers location and length - interrupts : Should contain WDT interrupt -Optional property: +Optional properties: - big-endian: If present the watchdog device's registers are implemented in big endian mode, otherwise in native mode(same with CPU), for more detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. +- fsl,ext-reset-output: If present the watchdog device is configured to + assert its external reset (WDOG_B) instead of issuing a software reset. Examples: diff --git a/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt b/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt new file mode 100644 index 000000000000..b9512f1eb80a --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/renesas-wdt.txt @@ -0,0 +1,25 @@ +Renesas Watchdog Timer (WDT) Controller + +Required properties: +- compatible : Should be "renesas,r8a7795-wdt", or "renesas,rcar-gen3-wdt" + + When compatible with the generic version, nodes must list the SoC-specific + version corresponding to the platform first, followed by the generic + version. + +- reg : Should contain WDT registers location and length +- clocks : the clock feeding the watchdog timer. + +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds +- power-domains : the power domain the WDT belongs to + +Examples: + + wdt0: watchdog@e6020000 { + compatible = "renesas,r8a7795-wdt", "renesas,rcar-gen3-wdt"; + reg = <0 0xe6020000 0 0x0c>; + clocks = <&cpg CPG_MOD 402>; + power-domains = <&cpg>; + timeout-sec = <60>; + }; diff --git a/Documentation/watchdog/hpwdt.txt b/Documentation/watchdog/hpwdt.txt index 9488078900e0..a40398cce9d1 100644 --- a/Documentation/watchdog/hpwdt.txt +++ b/Documentation/watchdog/hpwdt.txt @@ -1,64 +1,67 @@ -Last reviewed: 06/02/2009 +Last reviewed: 04/04/2016 - HP iLO2 NMI Watchdog Driver - NMI sourcing for iLO2 based ProLiant Servers + HPE iLO NMI Watchdog Driver + NMI sourcing for iLO based ProLiant Servers Documentation and Driver by - Thomas Mingarelli <thomas.mingarelli@hp.com> + Thomas Mingarelli <thomas.mingarelli@hpe.com> - The HP iLO2 NMI Watchdog driver is a kernel module that provides basic + The HPE iLO NMI Watchdog driver is a kernel module that provides basic watchdog functionality and the added benefit of NMI sourcing. Both the watchdog functionality and the NMI sourcing capability need to be enabled by the user. Remember that the two modes are not dependent on one another. A user can have the NMI sourcing without the watchdog timer and vice-versa. + All references to iLO in this document imply it also works on iLO2 and all + subsequent generations. Watchdog functionality is enabled like any other common watchdog driver. That is, an application needs to be started that kicks off the watchdog timer. A basic application exists in the Documentation/watchdog/src directory called watchdog-test.c. Simply compile the C file and kick it off. If the system - gets into a bad state and hangs, the HP ProLiant iLO 2 timer register will + gets into a bad state and hangs, the HPE ProLiant iLO timer register will not be updated in a timely fashion and a hardware system reset (also known as an Automatic Server Recovery (ASR)) event will occur. - The hpwdt driver also has four (4) module parameters. They are the following: + The hpwdt driver also has three (3) module parameters. They are the following: - soft_margin - allows the user to set the watchdog timer value - allow_kdump - allows the user to save off a kernel dump image after an NMI + soft_margin - allows the user to set the watchdog timer value. + Default value is 30 seconds. + allow_kdump - allows the user to save off a kernel dump image after an NMI. + Default value is 1/ON nowayout - basic watchdog parameter that does not allow the timer to be restarted or an impending ASR to be escaped. - priority - determines whether or not the hpwdt driver is first on the - die_notify list to handle NMIs or last. The default value - for this module parameter is 0 or LAST. If the user wants to - enable NMI sourcing then reload the hpwdt driver with - priority=1 (and boot with nmi_watchdog=0). + Default value is set when compiling the kernel. If it is set + to "Y", then there is no way of disabling the watchdog once + it has been started. NOTE: More information about watchdog drivers in general, including the ioctl interface to /dev/watchdog can be found in Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt. - The priority parameter was introduced due to other kernel software that relied - on handling NMIs (like oprofile). Keeping hpwdt's priority at 0 (or LAST) - enables the users of NMIs for non critical events to be work as expected. - The NMI sourcing capability is disabled by default due to the inability to distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the Linux kernel. What this means is that the hpwdt nmi handler code is called each time the NMI signal fires off. This could amount to several thousands of NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and confused" message in the logs or if the system gets into a hung state, then - the hpwdt driver can be reloaded with the "priority" module parameter set - (priority=1). + the hpwdt driver can be reloaded. 1. If the kernel has not been booted with nmi_watchdog turned off then - edit /boot/grub/menu.lst and place the nmi_watchdog=0 at the end of the - currently booting kernel line. + edit and place the nmi_watchdog=0 at the end of the currently booting + kernel line. Depending on your Linux distribution and platform setup: + For non-UEFI systems + /boot/grub/grub.conf or + /boot/grub/menu.lst + For UEFI systems + /boot/efi/EFI/distroname/grub.conf or + /boot/efi/efi/distroname/elilo.conf 2. reboot the sever - 3. Once the system comes up perform a rmmod hpwdt - 4. insmod /lib/modules/`uname -r`/kernel/drivers/char/watchdog/hpwdt.ko priority=1 + 3. Once the system comes up perform a modprobe -r hpwdt + 4. modprobe /lib/modules/`uname -r`/kernel/drivers/watchdog/hpwdt.ko Now, the hpwdt can successfully receive and source the NMI and provide a log - message that details the reason for the NMI (as determined by the HP BIOS). + message that details the reason for the NMI (as determined by the HPE BIOS). - Below is a list of NMIs the HP BIOS understands along with the associated + Below is a list of NMIs the HPE BIOS understands along with the associated code (reason): No source found 00h @@ -92,4 +95,4 @@ Last reviewed: 06/02/2009 -- Tom Mingarelli - (thomas.mingarelli@hp.com) + (thomas.mingarelli@hpe.com) diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt index c161399a6b5c..a8d364227a77 100644 --- a/Documentation/watchdog/watchdog-parameters.txt +++ b/Documentation/watchdog/watchdog-parameters.txt @@ -86,6 +86,10 @@ nowayout: Watchdog cannot be stopped once started davinci_wdt: heartbeat: Watchdog heartbeat period in seconds from 1 to 600, default 60 ------------------------------------------------- +ebc-c384_wdt: +timeout: Watchdog timeout in seconds. (1<=timeout<=15300, default=60) +nowayout: Watchdog cannot be stopped once started +------------------------------------------------- ep93xx_wdt: nowayout: Watchdog cannot be stopped once started timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=TBD) diff --git a/MAINTAINERS b/MAINTAINERS index 330200688228..7fb2603e3a95 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12345,6 +12345,7 @@ L: linux-watchdog@vger.kernel.org W: http://www.linux-watchdog.org/ T: git git://www.linux-watchdog.org/linux-watchdog.git S: Maintained +F: Documentation/devicetree/bindings/watchdog/ F: Documentation/watchdog/ F: drivers/watchdog/ F: include/linux/watchdog.h diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 89171505e750..fd2d74d0491e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -200,6 +200,8 @@ CONFIG_SENSORS_INA2XX=m CONFIG_THERMAL=y CONFIG_THERMAL_EMULATION=y CONFIG_EXYNOS_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_RENESAS_WDT=y CONFIG_MFD_SPMI_PMIC=y CONFIG_MFD_SEC_CORE=y CONFIG_MFD_HI655X_PMIC=y diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 5b45e277697b..b54f26c55dfd 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -661,6 +661,14 @@ config ATLAS7_WATCHDOG To compile this driver as a module, choose M here: the module will be called atlas7_wdt. +config RENESAS_WDT + tristate "Renesas WDT Watchdog" + depends on ARCH_RENESAS || COMPILE_TEST + select WATCHDOG_CORE + help + This driver adds watchdog support for the integrated watchdogs in the + Renesas R-Car and other SH-Mobile SoCs (usually named RWDT or SWDT). + # AVR32 Architecture config AT32AP700X_WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 9bde095ff691..a46e7c1380ac 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o +obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o # AVR32 Architecture obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 02007689e9ca..71ee07950e63 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -611,9 +611,7 @@ static int cpwd_probe(struct platform_device *op) } if (p->broken) { - init_timer(&cpwd_timer); - cpwd_timer.function = cpwd_brokentimer; - cpwd_timer.data = (unsigned long) p; + setup_timer(&cpwd_timer, cpwd_brokentimer, (unsigned long)p); cpwd_timer.expires = WD_BTIMEOUT; pr_info("PLD defect workaround enabled for model %s\n", diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 016bd9355190..d4ba262da7ba 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -38,7 +38,7 @@ #define SIO_F71808FG_LD_WDT 0x07 /* Watchdog timer logical device */ #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ -#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ +#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ #define SIO_REG_LDSEL 0x07 /* Logical device select */ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ @@ -59,6 +59,7 @@ #define SIO_F71869A_ID 0x1007 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F71889_ID 0x0723 /* Chipset ID */ +#define SIO_F81865_ID 0x0704 /* Chipset ID */ #define F71808FG_REG_WDO_CONF 0xf0 #define F71808FG_REG_WDT_CONF 0xf5 @@ -66,11 +67,14 @@ #define F71808FG_FLAG_WDOUT_EN 7 -#define F71808FG_FLAG_WDTMOUT_STS 5 +#define F71808FG_FLAG_WDTMOUT_STS 6 #define F71808FG_FLAG_WD_EN 5 #define F71808FG_FLAG_WD_PULSE 4 #define F71808FG_FLAG_WD_UNIT 3 +#define F81865_REG_WDO_CONF 0xfa +#define F81865_FLAG_WDOUT_EN 0 + /* Default values */ #define WATCHDOG_TIMEOUT 60 /* 1 minute default timeout */ #define WATCHDOG_MAX_TIMEOUT (60 * 255) @@ -112,7 +116,7 @@ module_param(start_withtimeout, uint, 0); MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" " given initial timeout. Zero (default) disables this feature."); -enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg }; +enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg, f81865 }; static const char *f71808e_names[] = { "f71808fg", @@ -121,6 +125,7 @@ static const char *f71808e_names[] = { "f71869", "f71882fg", "f71889fg", + "f81865", }; /* Super-I/O Function prototypes */ @@ -360,6 +365,11 @@ static int watchdog_start(void) superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf); break; + case f81865: + /* Set pin 70 to WDTRST# */ + superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 5); + break; + default: /* * 'default' label to shut up the compiler and catch @@ -371,8 +381,13 @@ static int watchdog_start(void) superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT); superio_set_bit(watchdog.sioaddr, SIO_REG_ENABLE, 0); - superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDO_CONF, - F71808FG_FLAG_WDOUT_EN); + + if (watchdog.type == f81865) + superio_set_bit(watchdog.sioaddr, F81865_REG_WDO_CONF, + F81865_FLAG_WDOUT_EN); + else + superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDO_CONF, + F71808FG_FLAG_WDOUT_EN); superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF, F71808FG_FLAG_WD_EN); @@ -655,7 +670,7 @@ static int __init watchdog_init(int sioaddr) superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT); wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF); - watchdog.caused_reboot = wdt_conf & F71808FG_FLAG_WDTMOUT_STS; + watchdog.caused_reboot = wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS); superio_exit(sioaddr); @@ -770,6 +785,9 @@ static int __init f71808e_find(int sioaddr) /* Confirmed (by datasheet) not to have a watchdog. */ err = -ENODEV; goto exit; + case SIO_F81865_ID: + watchdog.type = f81865; + break; default: pr_info("Unrecognized Fintek device: %04x\n", (unsigned int)devid); diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 331aed831dac..62f346bb4348 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -37,6 +37,8 @@ #define IMX2_WDT_WCR 0x00 /* Control Register */ #define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */ +#define IMX2_WDT_WCR_WDA (1 << 5) /* -> External Reset WDOG_B */ +#define IMX2_WDT_WCR_SRS (1 << 4) /* -> Software Reset Signal */ #define IMX2_WDT_WCR_WRE (1 << 3) /* -> WDOG Reset Enable */ #define IMX2_WDT_WCR_WDE (1 << 2) /* -> Watchdog Enable */ #define IMX2_WDT_WCR_WDZST (1 << 0) /* -> Watchdog timer Suspend */ @@ -59,6 +61,7 @@ struct imx2_wdt_device { struct clk *clk; struct regmap *regmap; struct watchdog_device wdog; + bool ext_reset; }; static bool nowayout = WATCHDOG_NOWAYOUT; @@ -83,6 +86,12 @@ static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action, struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); unsigned int wcr_enable = IMX2_WDT_WCR_WDE; + /* Use internal reset or external - not both */ + if (wdev->ext_reset) + wcr_enable |= IMX2_WDT_WCR_SRS; /* do not assert int reset */ + else + wcr_enable |= IMX2_WDT_WCR_WDA; /* do not assert ext-reset */ + /* Assert SRS signal */ regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable); /* @@ -112,8 +121,12 @@ static inline void imx2_wdt_setup(struct watchdog_device *wdog) val |= IMX2_WDT_WCR_WDZST; /* Strip the old watchdog Time-Out value */ val &= ~IMX2_WDT_WCR_WT; - /* Generate reset if WDOG times out */ - val &= ~IMX2_WDT_WCR_WRE; + /* Generate internal chip-level reset if WDOG times out */ + if (!wdev->ext_reset) + val &= ~IMX2_WDT_WCR_WRE; + /* Or if external-reset assert WDOG_B reset only on time-out */ + else + val |= IMX2_WDT_WCR_WRE; /* Keep Watchdog Disabled */ val &= ~IMX2_WDT_WCR_WDE; /* Set the watchdog's Time-Out value */ @@ -230,6 +243,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val); wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0; + wdev->ext_reset = of_property_read_bool(pdev->dev.of_node, + "fsl,ext-reset-output"); wdog->timeout = clamp_t(unsigned, timeout, 1, IMX2_WDT_MAX_TIME); if (wdog->timeout != timeout) dev_warn(&pdev->dev, "Initial timeout out of range! Clamped from %u to %u\n", diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index 6a7d5c365438..c8d51ddb26d5 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c @@ -160,10 +160,8 @@ static int jz4740_wdt_probe(struct platform_device *pdev) drvdata = devm_kzalloc(&pdev->dev, sizeof(struct jz4740_wdt_drvdata), GFP_KERNEL); - if (!drvdata) { - dev_err(&pdev->dev, "Unable to alloacate watchdog device\n"); + if (!drvdata) return -ENOMEM; - } if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) heartbeat = DEFAULT_HEARTBEAT; diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 14521c8b3d5a..b55981f88a08 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -431,7 +431,7 @@ static int octeon_wdt_cpu_callback(struct notifier_block *nfb, { unsigned int cpu = (unsigned long)hcpu; - switch (action) { + switch (action & ~CPU_TASKS_FROZEN) { case CPU_DOWN_PREPARE: octeon_wdt_disable_interrupt(cpu); break; diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index 20563ccb7be0..a043fa4f60e5 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -21,6 +21,7 @@ #define WDT_RST 0x38 #define WDT_EN 0x40 +#define WDT_STS 0x44 #define WDT_BITE_TIME 0x5C struct qcom_wdt { @@ -108,7 +109,8 @@ static const struct watchdog_ops qcom_wdt_ops = { static const struct watchdog_info qcom_wdt_info = { .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE - | WDIOF_SETTIMEOUT, + | WDIOF_SETTIMEOUT + | WDIOF_CARDRESET, .identity = KBUILD_MODNAME, }; @@ -171,6 +173,9 @@ static int qcom_wdt_probe(struct platform_device *pdev) wdt->wdd.max_timeout = 0x10000000U / wdt->rate; wdt->wdd.parent = &pdev->dev; + if (readl(wdt->base + WDT_STS) & 1) + wdt->wdd.bootstatus = WDIOF_CARDRESET; + /* * If 'timeout-sec' unspecified in devicetree, assume a 30 second * default, unless the max timeout is less than 30 seconds, then use diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c new file mode 100644 index 000000000000..cf61c92f7ecd --- /dev/null +++ b/drivers/watchdog/renesas_wdt.c @@ -0,0 +1,213 @@ +/* + * Watchdog driver for Renesas WDT watchdog + * + * Copyright (C) 2015-16 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com> + * Copyright (C) 2015-16 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/watchdog.h> + +#define RWTCNT 0 +#define RWTCSRA 4 +#define RWTCSRA_WOVF BIT(4) +#define RWTCSRA_WRFLG BIT(5) +#define RWTCSRA_TME BIT(7) + +#define RWDT_DEFAULT_TIMEOUT 60U + +static const unsigned int clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024 }; + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +struct rwdt_priv { + void __iomem *base; + struct watchdog_device wdev; + struct clk *clk; + unsigned int clks_per_sec; + u8 cks; +}; + +static void rwdt_write(struct rwdt_priv *priv, u32 val, unsigned int reg) +{ + if (reg == RWTCNT) + val |= 0x5a5a0000; + else + val |= 0xa5a5a500; + + writel_relaxed(val, priv->base + reg); +} + +static int rwdt_init_timeout(struct watchdog_device *wdev) +{ + struct rwdt_priv *priv = watchdog_get_drvdata(wdev); + + rwdt_write(priv, 65536 - wdev->timeout * priv->clks_per_sec, RWTCNT); + + return 0; +} + +static int rwdt_start(struct watchdog_device *wdev) +{ + struct rwdt_priv *priv = watchdog_get_drvdata(wdev); + + clk_prepare_enable(priv->clk); + + rwdt_write(priv, priv->cks, RWTCSRA); + rwdt_init_timeout(wdev); + + while (readb_relaxed(priv->base + RWTCSRA) & RWTCSRA_WRFLG) + cpu_relax(); + + rwdt_write(priv, priv->cks | RWTCSRA_TME, RWTCSRA); + + return 0; +} + +static int rwdt_stop(struct watchdog_device *wdev) +{ + struct rwdt_priv *priv = watchdog_get_drvdata(wdev); + + rwdt_write(priv, priv->cks, RWTCSRA); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static unsigned int rwdt_get_timeleft(struct watchdog_device *wdev) +{ + struct rwdt_priv *priv = watchdog_get_drvdata(wdev); + u16 val = readw_relaxed(priv->base + RWTCNT); + + return DIV_ROUND_CLOSEST(65536 - val, priv->clks_per_sec); +} + +static const struct watchdog_info rwdt_ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, + .identity = "Renesas WDT Watchdog", +}; + +static const struct watchdog_ops rwdt_ops = { + .owner = THIS_MODULE, + .start = rwdt_start, + .stop = rwdt_stop, + .ping = rwdt_init_timeout, + .get_timeleft = rwdt_get_timeleft, +}; + +static int rwdt_probe(struct platform_device *pdev) +{ + struct rwdt_priv *priv; + struct resource *res; + unsigned long rate; + unsigned int clks_per_sec; + int ret, i; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->clk)) + return PTR_ERR(priv->clk); + + rate = clk_get_rate(priv->clk); + if (!rate) + return -ENOENT; + + for (i = ARRAY_SIZE(clk_divs) - 1; i >= 0; i--) { + clks_per_sec = DIV_ROUND_UP(rate, clk_divs[i]); + if (clks_per_sec) { + priv->clks_per_sec = clks_per_sec; + priv->cks = i; + break; + } + } + + if (!clks_per_sec) { + dev_err(&pdev->dev, "Can't find suitable clock divider\n"); + return -ERANGE; + } + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + priv->wdev.info = &rwdt_ident, + priv->wdev.ops = &rwdt_ops, + priv->wdev.parent = &pdev->dev; + priv->wdev.min_timeout = 1; + priv->wdev.max_timeout = 65536 / clks_per_sec; + priv->wdev.timeout = min(priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT); + + platform_set_drvdata(pdev, priv); + watchdog_set_drvdata(&priv->wdev, priv); + watchdog_set_nowayout(&priv->wdev, nowayout); + + /* This overrides the default timeout only if DT configuration was found */ + ret = watchdog_init_timeout(&priv->wdev, 0, &pdev->dev); + if (ret) + dev_warn(&pdev->dev, "Specified timeout value invalid, using default\n"); + + ret = watchdog_register_device(&priv->wdev); + if (ret < 0) { + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return ret; + } + + return 0; +} + +static int rwdt_remove(struct platform_device *pdev) +{ + struct rwdt_priv *priv = platform_get_drvdata(pdev); + + watchdog_unregister_device(&priv->wdev); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +/* + * This driver does also fit for R-Car Gen2 (r8a779[0-4]) WDT. However, for SMP + * to work there, one also needs a RESET (RST) driver which does not exist yet + * due to HW issues. This needs to be solved before adding compatibles here. + */ +static const struct of_device_id rwdt_ids[] = { + { .compatible = "renesas,rcar-gen3-wdt", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rwdt_ids); + +static struct platform_driver rwdt_driver = { + .driver = { + .name = "renesas_wdt", + .of_match_table = rwdt_ids, + }, + .probe = rwdt_probe, + .remove = rwdt_remove, +}; +module_platform_driver(rwdt_driver); + +MODULE_DESCRIPTION("Renesas WDT Watchdog Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>"); diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index f90812170657..517a733175ef 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c @@ -275,9 +275,7 @@ static int sh_wdt_probe(struct platform_device *pdev) return rc; } - init_timer(&wdt->timer); - wdt->timer.function = sh_wdt_ping; - wdt->timer.data = (unsigned long)wdt; + setup_timer(&wdt->timer, sh_wdt_ping, (unsigned long)wdt); wdt->timer.expires = next_ping_period(clock_division_ratio); dev_info(&pdev->dev, "initialized.\n"); diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index 6467b91f2245..028618c5eeba 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c @@ -73,6 +73,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started." /* * Some TCO specific functions */ + +static bool tco_has_sp5100_reg_layout(struct pci_dev *dev) +{ + return dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && + dev->revision < 0x40; +} + static void tco_timer_start(void) { u32 val; @@ -129,7 +136,7 @@ static void tco_timer_enable(void) { int val; - if (sp5100_tco_pci->revision >= 0x40) { + if (!tco_has_sp5100_reg_layout(sp5100_tco_pci)) { /* For SB800 or later */ /* Set the Watchdog timer resolution to 1 sec */ outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG); @@ -342,8 +349,7 @@ static unsigned char sp5100_tco_setupdevice(void) /* * Determine type of southbridge chipset. */ - if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && - sp5100_tco_pci->revision < 0x40) { + if (tco_has_sp5100_reg_layout(sp5100_tco_pci)) { dev_name = SP5100_DEVNAME; index_reg = SP5100_IO_PM_INDEX_REG; data_reg = SP5100_IO_PM_DATA_REG; @@ -388,8 +394,7 @@ static unsigned char sp5100_tco_setupdevice(void) * Secondly, Find the watchdog timer MMIO address * from SBResource_MMIO register. */ - if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && - sp5100_tco_pci->revision < 0x40) { + if (tco_has_sp5100_reg_layout(sp5100_tco_pci)) { /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */ pci_read_config_dword(sp5100_tco_pci, SP5100_SB_RESOURCE_MMIO_BASE, &val); diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index 981a668b17e3..7c3ba58ae1be 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c @@ -104,7 +104,7 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd) * timeout module parameter (if it is valid value) or the timeout-sec property * (only if it is a valid value and the timeout_parm is out of bounds). * If none of them are valid then we keep the old value (which should normally - * be the default timeout value. + * be the default timeout value). * * A zero is returned on success and -EINVAL for failure. */ diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index e2c5abbb45ff..3595cffa24ea 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -736,7 +736,6 @@ static int watchdog_release(struct inode *inode, struct file *file) watchdog_ping(wdd); } - cancel_delayed_work_sync(&wd_data->work); watchdog_update_worker(wdd); /* make sure that /dev/watchdog can be re-opened */ |