Commit 1f93d2ab authored by Linus Torvalds's avatar Linus Torvalds

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
parents 48dd7cef 540be8b2
...@@ -5,10 +5,12 @@ Required properties: ...@@ -5,10 +5,12 @@ Required properties:
- reg : Should contain WDT registers location and length - reg : Should contain WDT registers location and length
- interrupts : Should contain WDT interrupt - interrupts : Should contain WDT interrupt
Optional property: Optional properties:
- big-endian: If present the watchdog device's registers are implemented - big-endian: If present the watchdog device's registers are implemented
in big endian mode, otherwise in native mode(same with CPU), for more in big endian mode, otherwise in native mode(same with CPU), for more
detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. 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: Examples:
......
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>;
};
Last reviewed: 06/02/2009 Last reviewed: 04/04/2016
HP iLO2 NMI Watchdog Driver HPE iLO NMI Watchdog Driver
NMI sourcing for iLO2 based ProLiant Servers NMI sourcing for iLO based ProLiant Servers
Documentation and Driver by 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 added benefit of NMI sourcing. Both the
watchdog functionality and the NMI sourcing capability need to be enabled 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. 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. 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 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 is, an application needs to be started that kicks off the watchdog timer. A
basic application exists in the Documentation/watchdog/src directory called 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 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 not be updated in a timely fashion and a hardware system reset (also known as
an Automatic Server Recovery (ASR)) event will occur. 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 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 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 nowayout - basic watchdog parameter that does not allow the timer to
be restarted or an impending ASR to be escaped. be restarted or an impending ASR to be escaped.
priority - determines whether or not the hpwdt driver is first on the Default value is set when compiling the kernel. If it is set
die_notify list to handle NMIs or last. The default value to "Y", then there is no way of disabling the watchdog once
for this module parameter is 0 or LAST. If the user wants to it has been started.
enable NMI sourcing then reload the hpwdt driver with
priority=1 (and boot with nmi_watchdog=0).
NOTE: More information about watchdog drivers in general, including the ioctl NOTE: More information about watchdog drivers in general, including the ioctl
interface to /dev/watchdog can be found in interface to /dev/watchdog can be found in
Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt. 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 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 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 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 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 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 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 the hpwdt driver can be reloaded.
(priority=1).
1. If the kernel has not been booted with nmi_watchdog turned off then 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 edit and place the nmi_watchdog=0 at the end of the currently booting
currently booting kernel line. 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 2. reboot the sever
3. Once the system comes up perform a rmmod hpwdt 3. Once the system comes up perform a modprobe -r hpwdt
4. insmod /lib/modules/`uname -r`/kernel/drivers/char/watchdog/hpwdt.ko priority=1 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 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): code (reason):
No source found 00h No source found 00h
...@@ -92,4 +95,4 @@ Last reviewed: 06/02/2009 ...@@ -92,4 +95,4 @@ Last reviewed: 06/02/2009
-- Tom Mingarelli -- Tom Mingarelli
(thomas.mingarelli@hp.com) (thomas.mingarelli@hpe.com)
...@@ -86,6 +86,10 @@ nowayout: Watchdog cannot be stopped once started ...@@ -86,6 +86,10 @@ nowayout: Watchdog cannot be stopped once started
davinci_wdt: davinci_wdt:
heartbeat: Watchdog heartbeat period in seconds from 1 to 600, default 60 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: ep93xx_wdt:
nowayout: Watchdog cannot be stopped once started nowayout: Watchdog cannot be stopped once started
timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=TBD) timeout: Watchdog timeout in seconds. (1<=timeout<=3600, default=TBD)
......
...@@ -12345,6 +12345,7 @@ L: linux-watchdog@vger.kernel.org ...@@ -12345,6 +12345,7 @@ L: linux-watchdog@vger.kernel.org
W: http://www.linux-watchdog.org/ W: http://www.linux-watchdog.org/
T: git git://www.linux-watchdog.org/linux-watchdog.git T: git git://www.linux-watchdog.org/linux-watchdog.git
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/watchdog/
F: Documentation/watchdog/ F: Documentation/watchdog/
F: drivers/watchdog/ F: drivers/watchdog/
F: include/linux/watchdog.h F: include/linux/watchdog.h
......
...@@ -200,6 +200,8 @@ CONFIG_SENSORS_INA2XX=m ...@@ -200,6 +200,8 @@ CONFIG_SENSORS_INA2XX=m
CONFIG_THERMAL=y CONFIG_THERMAL=y
CONFIG_THERMAL_EMULATION=y CONFIG_THERMAL_EMULATION=y
CONFIG_EXYNOS_THERMAL=y CONFIG_EXYNOS_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_RENESAS_WDT=y
CONFIG_MFD_SPMI_PMIC=y CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_SEC_CORE=y CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_HI655X_PMIC=y CONFIG_MFD_HI655X_PMIC=y
......
...@@ -661,6 +661,14 @@ config ATLAS7_WATCHDOG ...@@ -661,6 +661,14 @@ config ATLAS7_WATCHDOG
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called atlas7_wdt. 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 # AVR32 Architecture
config AT32AP700X_WDT config AT32AP700X_WDT
......
...@@ -73,6 +73,7 @@ obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o ...@@ -73,6 +73,7 @@ obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o
obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o
# AVR32 Architecture # AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
......
...@@ -611,9 +611,7 @@ static int cpwd_probe(struct platform_device *op) ...@@ -611,9 +611,7 @@ static int cpwd_probe(struct platform_device *op)
} }
if (p->broken) { if (p->broken) {
init_timer(&cpwd_timer); setup_timer(&cpwd_timer, cpwd_brokentimer, (unsigned long)p);
cpwd_timer.function = cpwd_brokentimer;
cpwd_timer.data = (unsigned long) p;
cpwd_timer.expires = WD_BTIMEOUT; cpwd_timer.expires = WD_BTIMEOUT;
pr_info("PLD defect workaround enabled for model %s\n", pr_info("PLD defect workaround enabled for model %s\n",
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#define SIO_F71808FG_LD_WDT 0x07 /* Watchdog timer logical device */ #define SIO_F71808FG_LD_WDT 0x07 /* Watchdog timer logical device */
#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ #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_LDSEL 0x07 /* Logical device select */
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#define SIO_F71869A_ID 0x1007 /* Chipset ID */ #define SIO_F71869A_ID 0x1007 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* 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_WDO_CONF 0xf0
#define F71808FG_REG_WDT_CONF 0xf5 #define F71808FG_REG_WDT_CONF 0xf5
...@@ -66,11 +67,14 @@ ...@@ -66,11 +67,14 @@
#define F71808FG_FLAG_WDOUT_EN 7 #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_EN 5
#define F71808FG_FLAG_WD_PULSE 4 #define F71808FG_FLAG_WD_PULSE 4
#define F71808FG_FLAG_WD_UNIT 3 #define F71808FG_FLAG_WD_UNIT 3
#define F81865_REG_WDO_CONF 0xfa
#define F81865_FLAG_WDOUT_EN 0
/* Default values */ /* Default values */
#define WATCHDOG_TIMEOUT 60 /* 1 minute default timeout */ #define WATCHDOG_TIMEOUT 60 /* 1 minute default timeout */
#define WATCHDOG_MAX_TIMEOUT (60 * 255) #define WATCHDOG_MAX_TIMEOUT (60 * 255)
...@@ -112,7 +116,7 @@ module_param(start_withtimeout, uint, 0); ...@@ -112,7 +116,7 @@ module_param(start_withtimeout, uint, 0);
MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
" given initial timeout. Zero (default) disables this feature."); " 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[] = { static const char *f71808e_names[] = {
"f71808fg", "f71808fg",
...@@ -121,6 +125,7 @@ static const char *f71808e_names[] = { ...@@ -121,6 +125,7 @@ static const char *f71808e_names[] = {
"f71869", "f71869",
"f71882fg", "f71882fg",
"f71889fg", "f71889fg",
"f81865",
}; };
/* Super-I/O Function prototypes */ /* Super-I/O Function prototypes */
...@@ -360,6 +365,11 @@ static int watchdog_start(void) ...@@ -360,6 +365,11 @@ static int watchdog_start(void)
superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf); superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf);
break; break;
case f81865:
/* Set pin 70 to WDTRST# */
superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 5);
break;
default: default:
/* /*
* 'default' label to shut up the compiler and catch * 'default' label to shut up the compiler and catch
...@@ -371,8 +381,13 @@ static int watchdog_start(void) ...@@ -371,8 +381,13 @@ static int watchdog_start(void)
superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT); superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
superio_set_bit(watchdog.sioaddr, SIO_REG_ENABLE, 0); 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, superio_set_bit(watchdog.sioaddr, F71808FG_REG_WDT_CONF,
F71808FG_FLAG_WD_EN); F71808FG_FLAG_WD_EN);
...@@ -655,7 +670,7 @@ static int __init watchdog_init(int sioaddr) ...@@ -655,7 +670,7 @@ static int __init watchdog_init(int sioaddr)
superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT); superio_select(watchdog.sioaddr, SIO_F71808FG_LD_WDT);
wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF); 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); superio_exit(sioaddr);
...@@ -770,6 +785,9 @@ static int __init f71808e_find(int sioaddr) ...@@ -770,6 +785,9 @@ static int __init f71808e_find(int sioaddr)
/* Confirmed (by datasheet) not to have a watchdog. */ /* Confirmed (by datasheet) not to have a watchdog. */
err = -ENODEV; err = -ENODEV;
goto exit; goto exit;
case SIO_F81865_ID:
watchdog.type = f81865;
break;
default: default:
pr_info("Unrecognized Fintek device: %04x\n", pr_info("Unrecognized Fintek device: %04x\n",
(unsigned int)devid); (unsigned int)devid);
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
#define IMX2_WDT_WCR 0x00 /* Control Register */ #define IMX2_WDT_WCR 0x00 /* Control Register */
#define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */ #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_WRE (1 << 3) /* -> WDOG Reset Enable */
#define IMX2_WDT_WCR_WDE (1 << 2) /* -> Watchdog Enable */ #define IMX2_WDT_WCR_WDE (1 << 2) /* -> Watchdog Enable */
#define IMX2_WDT_WCR_WDZST (1 << 0) /* -> Watchdog timer Suspend */ #define IMX2_WDT_WCR_WDZST (1 << 0) /* -> Watchdog timer Suspend */
...@@ -59,6 +61,7 @@ struct imx2_wdt_device { ...@@ -59,6 +61,7 @@ struct imx2_wdt_device {
struct clk *clk; struct clk *clk;
struct regmap *regmap; struct regmap *regmap;
struct watchdog_device wdog; struct watchdog_device wdog;
bool ext_reset;
}; };
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
...@@ -83,6 +86,12 @@ static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action, ...@@ -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); struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
unsigned int wcr_enable = IMX2_WDT_WCR_WDE; 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 */ /* Assert SRS signal */
regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable); regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
/* /*
...@@ -112,8 +121,12 @@ static inline void imx2_wdt_setup(struct watchdog_device *wdog) ...@@ -112,8 +121,12 @@ static inline void imx2_wdt_setup(struct watchdog_device *wdog)
val |= IMX2_WDT_WCR_WDZST; val |= IMX2_WDT_WCR_WDZST;
/* Strip the old watchdog Time-Out value */ /* Strip the old watchdog Time-Out value */
val &= ~IMX2_WDT_WCR_WT; val &= ~IMX2_WDT_WCR_WT;
/* Generate reset if WDOG times out */ /* Generate internal chip-level reset if WDOG times out */
val &= ~IMX2_WDT_WCR_WRE; 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 */ /* Keep Watchdog Disabled */
val &= ~IMX2_WDT_WCR_WDE; val &= ~IMX2_WDT_WCR_WDE;
/* Set the watchdog's Time-Out value */ /* Set the watchdog's Time-Out value */
...@@ -230,6 +243,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) ...@@ -230,6 +243,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val); regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val);
wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0; 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); wdog->timeout = clamp_t(unsigned, timeout, 1, IMX2_WDT_MAX_TIME);
if (wdog->timeout != timeout) if (wdog->timeout != timeout)
dev_warn(&pdev->dev, "Initial timeout out of range! Clamped from %u to %u\n", dev_warn(&pdev->dev, "Initial timeout out of range! Clamped from %u to %u\n",
......
...@@ -160,10 +160,8 @@ static int jz4740_wdt_probe(struct platform_device *pdev) ...@@ -160,10 +160,8 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct jz4740_wdt_drvdata), drvdata = devm_kzalloc(&pdev->dev, sizeof(struct jz4740_wdt_drvdata),
GFP_KERNEL); GFP_KERNEL);
if (!drvdata) { if (!drvdata)
dev_err(&pdev->dev, "Unable to alloacate watchdog device\n");
return -ENOMEM; return -ENOMEM;
}
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT; heartbeat = DEFAULT_HEARTBEAT;
......
...@@ -431,7 +431,7 @@ static int octeon_wdt_cpu_callback(struct notifier_block *nfb, ...@@ -431,7 +431,7 @@ static int octeon_wdt_cpu_callback(struct notifier_block *nfb,
{ {
unsigned int cpu = (unsigned long)hcpu; unsigned int cpu = (unsigned long)hcpu;
switch (action) { switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE:
octeon_wdt_disable_interrupt(cpu); octeon_wdt_disable_interrupt(cpu);
break; break;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define WDT_RST 0x38 #define WDT_RST 0x38
#define WDT_EN 0x40 #define WDT_EN 0x40
#define WDT_STS 0x44
#define WDT_BITE_TIME 0x5C #define WDT_BITE_TIME 0x5C
struct qcom_wdt { struct qcom_wdt {
...@@ -108,7 +109,8 @@ static const struct watchdog_ops qcom_wdt_ops = { ...@@ -108,7 +109,8 @@ static const struct watchdog_ops qcom_wdt_ops = {
static const struct watchdog_info qcom_wdt_info = { static const struct watchdog_info qcom_wdt_info = {
.options = WDIOF_KEEPALIVEPING .options = WDIOF_KEEPALIVEPING
| WDIOF_MAGICCLOSE | WDIOF_MAGICCLOSE
| WDIOF_SETTIMEOUT, | WDIOF_SETTIMEOUT
| WDIOF_CARDRESET,
.identity = KBUILD_MODNAME, .identity = KBUILD_MODNAME,
}; };
...@@ -171,6 +173,9 @@ static int qcom_wdt_probe(struct platform_device *pdev) ...@@ -171,6 +173,9 @@ static int qcom_wdt_probe(struct platform_device *pdev)
wdt->wdd.max_timeout = 0x10000000U / wdt->rate; wdt->wdd.max_timeout = 0x10000000U / wdt->rate;
wdt->wdd.parent = &pdev->dev; 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 * If 'timeout-sec' unspecified in devicetree, assume a 30 second
* default, unless the max timeout is less than 30 seconds, then use * default, unless the max timeout is less than 30 seconds, then use
......
/*
* 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>");
...@@ -275,9 +275,7 @@ static int sh_wdt_probe(struct platform_device *pdev) ...@@ -275,9 +275,7 @@ static int sh_wdt_probe(struct platform_device *pdev)
return rc; return rc;
} }
init_timer(&wdt->timer); setup_timer(&wdt->timer, sh_wdt_ping, (unsigned long)wdt);
wdt->timer.function = sh_wdt_ping;
wdt->timer.data = (unsigned long)wdt;
wdt->timer.expires = next_ping_period(clock_division_ratio); wdt->timer.expires = next_ping_period(clock_division_ratio);
dev_info(&pdev->dev, "initialized.\n"); dev_info(&pdev->dev, "initialized.\n");
......
...@@ -73,6 +73,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started." ...@@ -73,6 +73,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started."
/* /*
* Some TCO specific functions * 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) static void tco_timer_start(void)
{ {
u32 val; u32 val;
...@@ -129,7 +136,7 @@ static void tco_timer_enable(void) ...@@ -129,7 +136,7 @@ static void tco_timer_enable(void)
{ {
int val; int val;
if (sp5100_tco_pci->revision >= 0x40) { if (!tco_has_sp5100_reg_layout(sp5100_tco_pci)) {
/* For SB800 or later */ /* For SB800 or later */
/* Set the Watchdog timer resolution to 1 sec */ /* Set the Watchdog timer resolution to 1 sec */
outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG); outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG);
...@@ -342,8 +349,7 @@ static unsigned char sp5100_tco_setupdevice(void) ...@@ -342,8 +349,7 @@ static unsigned char sp5100_tco_setupdevice(void)
/* /*
* Determine type of southbridge chipset. * Determine type of southbridge chipset.
*/ */
if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && if (tco_has_sp5100_reg_layout(sp5100_tco_pci)) {
sp5100_tco_pci->revision < 0x40) {
dev_name = SP5100_DEVNAME; dev_name = SP5100_DEVNAME;
index_reg = SP5100_IO_PM_INDEX_REG; index_reg = SP5100_IO_PM_INDEX_REG;
data_reg = SP5100_IO_PM_DATA_REG; data_reg = SP5100_IO_PM_DATA_REG;
...@@ -388,8 +394,7 @@ static unsigned char sp5100_tco_setupdevice(void) ...@@ -388,8 +394,7 @@ static unsigned char sp5100_tco_setupdevice(void)
* Secondly, Find the watchdog timer MMIO address * Secondly, Find the watchdog timer MMIO address
* from SBResource_MMIO register. * from SBResource_MMIO register.
*/ */
if (sp5100_tco_pci->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && if (tco_has_sp5100_reg_layout(sp5100_tco_pci)) {
sp5100_tco_pci->revision < 0x40) {
/* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */ /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
pci_read_config_dword(sp5100_tco_pci, pci_read_config_dword(sp5100_tco_pci,
SP5100_SB_RESOURCE_MMIO_BASE, &val); SP5100_SB_RESOURCE_MMIO_BASE, &val);
......
...@@ -104,7 +104,7 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd) ...@@ -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 * 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). * (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 * 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. * A zero is returned on success and -EINVAL for failure.
*/ */
......
...@@ -736,7 +736,6 @@ static int watchdog_release(struct inode *inode, struct file *file) ...@@ -736,7 +736,6 @@ static int watchdog_release(struct inode *inode, struct file *file)
watchdog_ping(wdd); watchdog_ping(wdd);
} }
cancel_delayed_work_sync(&wd_data->work);
watchdog_update_worker(wdd); watchdog_update_worker(wdd);
/* make sure that /dev/watchdog can be re-opened */ /* make sure that /dev/watchdog can be re-opened */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment