Commit 6755f456 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux-watchdog-5.11-rc1' of git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:

 - Removal of the pnx83xx driver

 - Add a binding for A100's watchdog controller

 - Add Rockchip compatibles to snps,dw-wdt.yaml

 - hpwdt: Disable NMI in Crash Kernel

 - Fix potential dereferencing of null pointer in watchdog_core

 - Several other small fixes and improvements

* tag 'linux-watchdog-5.11-rc1' of git://www.linux-watchdog.org/linux-watchdog: (23 commits)
  watchdog: convert comma to semicolon
  watchdog: iTCO_wdt: use dev_*() instead of pr_*() for logging
  dt-binding: watchdog: add Rockchip compatibles to snps,dw-wdt.yaml
  watchdog: coh901327: add COMMON_CLK dependency
  dt-bindings: watchdog: sun4i: Add A100 compatible
  watchdog: qcom: Avoid context switch in restart handler
  watchdog: iTCO_wdt: use module_platform_device() macro
  watchdog: Fix potential dereferencing of null pointer
  watchdog: wdat_wdt: Fix missing kerneldoc reported by W=1
  watchdog/hpwdt: Reflect changes
  watchdog/hpwdt: Disable NMI in Crash Kernel
  wdt: sp805: add watchdog_stop on reboot
  watchdog: sbc_fitpc2_wdt: add __user annotations
  watchdog: geodewdt: remove unneeded break
  watchdog: rti-wdt: fix reference leak in rti_wdt_probe
  watchdog: qcom_wdt: set WDOG_HW_RUNNING bit when appropriate
  watchdog: remove pnx83xx driver
  watchdog: stm32_iwdg: don't print an error on probe deferral
  watchdog: sprd: change to use usleep_range() instead of busy loop
  watchdog: sprd: check busy bit before new loading rather than after that
  ...
parents 614cb589 0b9491b6
...@@ -21,6 +21,9 @@ properties: ...@@ -21,6 +21,9 @@ properties:
- items: - items:
- const: allwinner,sun50i-a64-wdt - const: allwinner,sun50i-a64-wdt
- const: allwinner,sun6i-a31-wdt - const: allwinner,sun6i-a31-wdt
- items:
- const: allwinner,sun50i-a100-wdt
- const: allwinner,sun6i-a31-wdt
- items: - items:
- const: allwinner,sun50i-h6-wdt - const: allwinner,sun50i-h6-wdt
- const: allwinner,sun6i-a31-wdt - const: allwinner,sun6i-a31-wdt
......
...@@ -14,7 +14,15 @@ maintainers: ...@@ -14,7 +14,15 @@ maintainers:
properties: properties:
compatible: compatible:
const: snps,dw-wdt oneOf:
- const: snps,dw-wdt
- items:
- enum:
- rockchip,rk3066-wdt
- rockchip,rk3188-wdt
- rockchip,rk3288-wdt
- rockchip,rk3368-wdt
- const: snps,dw-wdt
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -386,6 +386,7 @@ config ARM_SBSA_WATCHDOG ...@@ -386,6 +386,7 @@ config ARM_SBSA_WATCHDOG
config ARMADA_37XX_WATCHDOG config ARMADA_37XX_WATCHDOG
tristate "Armada 37xx watchdog" tristate "Armada 37xx watchdog"
depends on ARCH_MVEBU || COMPILE_TEST depends on ARCH_MVEBU || COMPILE_TEST
depends on HAS_IOMEM
select MFD_SYSCON select MFD_SYSCON
select WATCHDOG_CORE select WATCHDOG_CORE
help help
...@@ -631,7 +632,7 @@ config SUNXI_WATCHDOG ...@@ -631,7 +632,7 @@ config SUNXI_WATCHDOG
config COH901327_WATCHDOG config COH901327_WATCHDOG
bool "ST-Ericsson COH 901 327 watchdog" bool "ST-Ericsson COH 901 327 watchdog"
depends on ARCH_U300 || (ARM && COMPILE_TEST) depends on ARCH_U300 || (ARM && COMMON_CLK && COMPILE_TEST)
default y if MACH_U300 default y if MACH_U300
select WATCHDOG_CORE select WATCHDOG_CORE
help help
...@@ -789,6 +790,7 @@ config MOXART_WDT ...@@ -789,6 +790,7 @@ config MOXART_WDT
config SIRFSOC_WATCHDOG config SIRFSOC_WATCHDOG
tristate "SiRFSOC watchdog" tristate "SiRFSOC watchdog"
depends on HAS_IOMEM
depends on ARCH_SIRF || COMPILE_TEST depends on ARCH_SIRF || COMPILE_TEST
select WATCHDOG_CORE select WATCHDOG_CORE
default y default y
...@@ -1696,16 +1698,6 @@ config WDT_MTX1 ...@@ -1696,16 +1698,6 @@ config WDT_MTX1
Hardware driver for the MTX-1 boards. This is a watchdog timer that Hardware driver for the MTX-1 boards. This is a watchdog timer that
will reboot the machine after a 100 seconds timer expired. will reboot the machine after a 100 seconds timer expired.
config PNX833X_WDT
tristate "PNX833x Hardware Watchdog"
depends on SOC_PNX8335
depends on BROKEN
help
Hardware driver for the PNX833x's watchdog. This is a
watchdog timer that will reboot the machine after a programmable
timer has expired and no process has written to /dev/watchdog during
that time.
config SIBYTE_WDOG config SIBYTE_WDOG
tristate "Sibyte SoC hardware watchdog" tristate "Sibyte SoC hardware watchdog"
depends on CPU_SB1 || (MIPS && COMPILE_TEST) depends on CPU_SB1 || (MIPS && COMPILE_TEST)
......
...@@ -161,7 +161,6 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o ...@@ -161,7 +161,6 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
obj-$(CONFIG_AR7_WDT) += ar7_wdt.o obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
......
...@@ -150,8 +150,6 @@ static long geodewdt_ioctl(struct file *file, unsigned int cmd, ...@@ -150,8 +150,6 @@ static long geodewdt_ioctl(struct file *file, unsigned int cmd,
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0; sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
......
...@@ -21,8 +21,9 @@ ...@@ -21,8 +21,9 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <linux/crash_dump.h>
#define HPWDT_VERSION "2.0.3" #define HPWDT_VERSION "2.0.4"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TICKS 65535 #define HPWDT_MAX_TICKS 65535
...@@ -334,6 +335,11 @@ static int hpwdt_init_one(struct pci_dev *dev, ...@@ -334,6 +335,11 @@ static int hpwdt_init_one(struct pci_dev *dev,
watchdog_set_nowayout(&hpwdt_dev, nowayout); watchdog_set_nowayout(&hpwdt_dev, nowayout);
watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL); watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
if (is_kdump_kernel()) {
pretimeout = 0;
kdumptimeout = 0;
}
if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) { if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n"); dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
pretimeout = 0; pretimeout = 0;
......
...@@ -40,8 +40,6 @@ ...@@ -40,8 +40,6 @@
* Includes, defines, variables, module parameters, ... * Includes, defines, variables, module parameters, ...
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* Module and version information */ /* Module and version information */
#define DRV_NAME "iTCO_wdt" #define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.11" #define DRV_VERSION "1.11"
...@@ -279,7 +277,7 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev) ...@@ -279,7 +277,7 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev)
/* disable chipset's NO_REBOOT bit */ /* disable chipset's NO_REBOOT bit */
if (p->update_no_reboot_bit(p->no_reboot_priv, false)) { if (p->update_no_reboot_bit(p->no_reboot_priv, false)) {
spin_unlock(&p->io_lock); spin_unlock(&p->io_lock);
pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); dev_err(wd_dev->parent, "failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n");
return -EIO; return -EIO;
} }
...@@ -510,7 +508,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev) ...@@ -510,7 +508,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
/* Check chipset's NO_REBOOT bit */ /* Check chipset's NO_REBOOT bit */
if (p->update_no_reboot_bit(p->no_reboot_priv, false) && if (p->update_no_reboot_bit(p->no_reboot_priv, false) &&
iTCO_vendor_check_noreboot_on()) { iTCO_vendor_check_noreboot_on()) {
pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); dev_info(dev, "unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
return -ENODEV; /* Cannot reset NO_REBOOT bit */ return -ENODEV; /* Cannot reset NO_REBOOT bit */
} }
...@@ -530,12 +528,12 @@ static int iTCO_wdt_probe(struct platform_device *pdev) ...@@ -530,12 +528,12 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
if (!devm_request_region(dev, p->tco_res->start, if (!devm_request_region(dev, p->tco_res->start,
resource_size(p->tco_res), resource_size(p->tco_res),
pdev->name)) { pdev->name)) {
pr_err("I/O address 0x%04llx already in use, device disabled\n", dev_err(dev, "I/O address 0x%04llx already in use, device disabled\n",
(u64)TCOBASE(p)); (u64)TCOBASE(p));
return -EBUSY; return -EBUSY;
} }
pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n", dev_info(dev, "Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n",
pdata->name, pdata->version, (u64)TCOBASE(p)); pdata->name, pdata->version, (u64)TCOBASE(p));
/* Clear out the (probably old) status */ /* Clear out the (probably old) status */
...@@ -558,7 +556,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev) ...@@ -558,7 +556,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
break; break;
} }
p->wddev.info = &ident, p->wddev.info = &ident,
p->wddev.ops = &iTCO_wdt_ops, p->wddev.ops = &iTCO_wdt_ops,
p->wddev.bootstatus = 0; p->wddev.bootstatus = 0;
p->wddev.timeout = WATCHDOG_TIMEOUT; p->wddev.timeout = WATCHDOG_TIMEOUT;
...@@ -575,7 +573,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev) ...@@ -575,7 +573,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
if not reset to the default */ if not reset to the default */
if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) { if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) {
iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT); iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT);
pr_info("timeout value out of range, using %d\n", dev_info(dev, "timeout value out of range, using %d\n",
WATCHDOG_TIMEOUT); WATCHDOG_TIMEOUT);
} }
...@@ -583,11 +581,11 @@ static int iTCO_wdt_probe(struct platform_device *pdev) ...@@ -583,11 +581,11 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_unregister(&p->wddev); watchdog_stop_on_unregister(&p->wddev);
ret = devm_watchdog_register_device(dev, &p->wddev); ret = devm_watchdog_register_device(dev, &p->wddev);
if (ret != 0) { if (ret != 0) {
pr_err("cannot register watchdog device (err=%d)\n", ret); dev_err(dev, "cannot register watchdog device (err=%d)\n", ret);
return ret; return ret;
} }
pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n", dev_info(dev, "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout); heartbeat, nowayout);
return 0; return 0;
...@@ -651,21 +649,7 @@ static struct platform_driver iTCO_wdt_driver = { ...@@ -651,21 +649,7 @@ static struct platform_driver iTCO_wdt_driver = {
}, },
}; };
static int __init iTCO_wdt_init_module(void) module_platform_driver(iTCO_wdt_driver);
{
pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION);
return platform_driver_register(&iTCO_wdt_driver);
}
static void __exit iTCO_wdt_cleanup_module(void)
{
platform_driver_unregister(&iTCO_wdt_driver);
pr_info("Watchdog Module Unloaded\n");
}
module_init(iTCO_wdt_init_module);
module_exit(iTCO_wdt_cleanup_module);
MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver"); MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
......
...@@ -175,8 +175,8 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) ...@@ -175,8 +175,8 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
spin_lock_init(&ddata->lock); spin_lock_init(&ddata->lock);
ddata->wdd.info = &mpc8xxx_wdt_info, ddata->wdd.info = &mpc8xxx_wdt_info;
ddata->wdd.ops = &mpc8xxx_wdt_ops, ddata->wdd.ops = &mpc8xxx_wdt_ops;
ddata->wdd.timeout = WATCHDOG_TIMEOUT; ddata->wdd.timeout = WATCHDOG_TIMEOUT;
watchdog_init_timeout(&ddata->wdd, timeout, dev); watchdog_init_timeout(&ddata->wdd, timeout, dev);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PNX833x Hardware Watchdog Driver
* Copyright 2008 NXP Semiconductors
* Daniel Laird <daniel.j.laird@nxp.com>
* Andre McCurdy <andre.mccurdy@nxp.com>
*
* Heavily based upon - IndyDog 0.3
* A Hardware Watchdog Device for SGI IP22
*
* (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
*
* based on softdog.c by Alan Cox <alan@redhat.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <asm/mach-pnx833x/pnx833x.h>
#define WATCHDOG_TIMEOUT 30 /* 30 sec Maximum timeout */
#define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
#define PNX_WATCHDOG_TIMEOUT (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY)
#define PNX_TIMEOUT_VALUE 2040000000U
/** CONFIG block */
#define PNX833X_CONFIG (0x07000U)
#define PNX833X_CONFIG_CPU_WATCHDOG (0x54)
#define PNX833X_CONFIG_CPU_WATCHDOG_COMPARE (0x58)
#define PNX833X_CONFIG_CPU_COUNTERS_CONTROL (0x1c)
/** RESET block */
#define PNX833X_RESET (0x08000U)
#define PNX833X_RESET_CONFIG (0x08)
static int pnx833x_wdt_alive;
/* Set default timeout in MHZ.*/
static int pnx833x_wdt_timeout = PNX_WATCHDOG_TIMEOUT;
module_param(pnx833x_wdt_timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
__MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds).");
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) ")");
#define START_DEFAULT 1
static int start_enabled = START_DEFAULT;
module_param(start_enabled, int, 0);
MODULE_PARM_DESC(start_enabled, "Watchdog is started on module insertion "
"(default=" __MODULE_STRING(START_DEFAULT) ")");
static void pnx833x_wdt_start(void)
{
/* Enable watchdog causing reset. */
PNX833X_REG(PNX833X_RESET + PNX833X_RESET_CONFIG) |= 0x1;
/* Set timeout.*/
PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
/* Enable watchdog. */
PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
pr_info("Started watchdog timer\n");
}
static void pnx833x_wdt_stop(void)
{
/* Disable watchdog causing reset. */
PNX833X_REG(PNX833X_RESET + PNX833X_CONFIG) &= 0xFFFFFFFE;
/* Disable watchdog.*/
PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
pr_info("Stopped watchdog timer\n");
}
static void pnx833x_wdt_ping(void)
{
PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
}
/*
* Allow only one person to hold it open
*/
static int pnx833x_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(0, &pnx833x_wdt_alive))
return -EBUSY;
if (nowayout)
__module_get(THIS_MODULE);
/* Activate timer */
if (!start_enabled)
pnx833x_wdt_start();
pnx833x_wdt_ping();
pr_info("Started watchdog timer\n");
return stream_open(inode, file);
}
static int pnx833x_wdt_release(struct inode *inode, struct file *file)
{
/* Shut off the timer.
* Lock it in if it's a module and we defined ...NOWAYOUT */
if (!nowayout)
pnx833x_wdt_stop(); /* Turn the WDT off */
clear_bit(0, &pnx833x_wdt_alive);
return 0;
}
static ssize_t pnx833x_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
{
/* Refresh the timer. */
if (len)
pnx833x_wdt_ping();
return len;
}
static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int options, new_timeout = 0;
uint32_t timeout, timeout_left = 0;
static const struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
.firmware_version = 0,
.identity = "Hardware Watchdog for PNX833x",
};
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg,
&ident, sizeof(ident)))
return -EFAULT;
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int *)arg);
case WDIOC_SETOPTIONS:
if (get_user(options, (int *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD)
pnx833x_wdt_stop();
if (options & WDIOS_ENABLECARD)
pnx833x_wdt_start();
return 0;
case WDIOC_KEEPALIVE:
pnx833x_wdt_ping();
return 0;
case WDIOC_SETTIMEOUT:
{
if (get_user(new_timeout, (int *)arg))
return -EFAULT;
pnx833x_wdt_timeout = new_timeout;
PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = new_timeout;
return put_user(new_timeout, (int *)arg);
}
case WDIOC_GETTIMEOUT:
timeout = PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_WATCHDOG_COMPARE);
return put_user(timeout, (int *)arg);
case WDIOC_GETTIMELEFT:
timeout_left = PNX833X_REG(PNX833X_CONFIG +
PNX833X_CONFIG_CPU_WATCHDOG);
return put_user(timeout_left, (int *)arg);
}
}
static int pnx833x_wdt_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{
if (code == SYS_DOWN || code == SYS_HALT)
pnx833x_wdt_stop(); /* Turn the WDT off */
return NOTIFY_DONE;
}
static const struct file_operations pnx833x_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pnx833x_wdt_write,
.unlocked_ioctl = pnx833x_wdt_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.open = pnx833x_wdt_open,
.release = pnx833x_wdt_release,
};
static struct miscdevice pnx833x_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &pnx833x_wdt_fops,
};
static struct notifier_block pnx833x_wdt_notifier = {
.notifier_call = pnx833x_wdt_notify_sys,
};
static int __init watchdog_init(void)
{
int ret, cause;
/* Lets check the reason for the reset.*/
cause = PNX833X_REG(PNX833X_RESET);
/*If bit 31 is set then watchdog was cause of reset.*/
if (cause & 0x80000000) {
pr_info("The system was previously reset due to the watchdog firing - please investigate...\n");
}
ret = register_reboot_notifier(&pnx833x_wdt_notifier);
if (ret) {
pr_err("cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&pnx833x_wdt_miscdev);
if (ret) {
pr_err("cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&pnx833x_wdt_notifier);
return ret;
}
pr_info("Hardware Watchdog Timer for PNX833x: Version 0.1\n");
if (start_enabled)
pnx833x_wdt_start();
return 0;
}
static void __exit watchdog_exit(void)
{
misc_deregister(&pnx833x_wdt_miscdev);
unregister_reboot_notifier(&pnx833x_wdt_notifier);
}
module_init(watchdog_init);
module_exit(watchdog_exit);
MODULE_AUTHOR("Daniel Laird/Andre McCurdy");
MODULE_DESCRIPTION("Hardware Watchdog Device for PNX833x");
MODULE_LICENSE("GPL");
...@@ -148,10 +148,17 @@ static int qcom_wdt_restart(struct watchdog_device *wdd, unsigned long action, ...@@ -148,10 +148,17 @@ static int qcom_wdt_restart(struct watchdog_device *wdd, unsigned long action,
*/ */
wmb(); wmb();
msleep(150); mdelay(150);
return 0; return 0;
} }
static int qcom_wdt_is_running(struct watchdog_device *wdd)
{
struct qcom_wdt *wdt = to_qcom_wdt(wdd);
return (readl(wdt_addr(wdt, WDT_EN)) & QCOM_WDT_ENABLE);
}
static const struct watchdog_ops qcom_wdt_ops = { static const struct watchdog_ops qcom_wdt_ops = {
.start = qcom_wdt_start, .start = qcom_wdt_start,
.stop = qcom_wdt_stop, .stop = qcom_wdt_stop,
...@@ -294,6 +301,17 @@ static int qcom_wdt_probe(struct platform_device *pdev) ...@@ -294,6 +301,17 @@ static int qcom_wdt_probe(struct platform_device *pdev)
wdt->wdd.timeout = min(wdt->wdd.max_timeout, 30U); wdt->wdd.timeout = min(wdt->wdd.max_timeout, 30U);
watchdog_init_timeout(&wdt->wdd, 0, dev); watchdog_init_timeout(&wdt->wdd, 0, dev);
/*
* If WDT is already running, call WDT start which
* will stop the WDT, set timeouts as bootloader
* might use different ones and set running bit
* to inform the WDT subsystem to ping the WDT
*/
if (qcom_wdt_is_running(&wdt->wdd)) {
qcom_wdt_start(&wdt->wdd);
set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
}
ret = devm_watchdog_register_device(dev, &wdt->wdd); ret = devm_watchdog_register_device(dev, &wdt->wdd);
if (ret) if (ret)
return ret; return ret;
......
...@@ -227,8 +227,10 @@ static int rti_wdt_probe(struct platform_device *pdev) ...@@ -227,8 +227,10 @@ static int rti_wdt_probe(struct platform_device *pdev)
pm_runtime_enable(dev); pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev); ret = pm_runtime_get_sync(dev);
if (ret) if (ret) {
pm_runtime_put_noidle(dev);
return dev_err_probe(dev, ret, "runtime pm failed\n"); return dev_err_probe(dev, ret, "runtime pm failed\n");
}
platform_set_drvdata(pdev, wdt); platform_set_drvdata(pdev, wdt);
......
...@@ -78,7 +78,7 @@ static int fitpc2_wdt_open(struct inode *inode, struct file *file) ...@@ -78,7 +78,7 @@ static int fitpc2_wdt_open(struct inode *inode, struct file *file)
return stream_open(inode, file); return stream_open(inode, file);
} }
static ssize_t fitpc2_wdt_write(struct file *file, const char *data, static ssize_t fitpc2_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
size_t i; size_t i;
...@@ -125,16 +125,16 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -125,16 +125,16 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd,
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
ret = copy_to_user((struct watchdog_info *)arg, &ident, ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident)) ? -EFAULT : 0; sizeof(ident)) ? -EFAULT : 0;
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg); ret = put_user(0, (int __user *)arg);
break; break;
case WDIOC_GETBOOTSTATUS: case WDIOC_GETBOOTSTATUS:
ret = put_user(0, (int *)arg); ret = put_user(0, (int __user *)arg);
break; break;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
...@@ -143,7 +143,7 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -143,7 +143,7 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd,
break; break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg); ret = get_user(time, (int __user *)arg);
if (ret) if (ret)
break; break;
...@@ -157,7 +157,7 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -157,7 +157,7 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd,
fallthrough; fallthrough;
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
ret = put_user(margin, (int *)arg); ret = put_user(margin, (int __user *)arg);
break; break;
} }
......
...@@ -291,6 +291,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) ...@@ -291,6 +291,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
} }
watchdog_stop_on_reboot(&wdt->wdd);
ret = watchdog_register_device(&wdt->wdd); ret = watchdog_register_device(&wdt->wdd);
if (ret) if (ret)
goto err; goto err;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -53,7 +54,7 @@ ...@@ -53,7 +54,7 @@
#define SPRD_WDT_CNT_HIGH_SHIFT 16 #define SPRD_WDT_CNT_HIGH_SHIFT 16
#define SPRD_WDT_LOW_VALUE_MASK GENMASK(15, 0) #define SPRD_WDT_LOW_VALUE_MASK GENMASK(15, 0)
#define SPRD_WDT_LOAD_TIMEOUT 1000 #define SPRD_WDT_LOAD_TIMEOUT 11
struct sprd_wdt { struct sprd_wdt {
void __iomem *base; void __iomem *base;
...@@ -108,6 +109,23 @@ static int sprd_wdt_load_value(struct sprd_wdt *wdt, u32 timeout, ...@@ -108,6 +109,23 @@ static int sprd_wdt_load_value(struct sprd_wdt *wdt, u32 timeout,
u32 tmr_step = timeout * SPRD_WDT_CNT_STEP; u32 tmr_step = timeout * SPRD_WDT_CNT_STEP;
u32 prtmr_step = pretimeout * SPRD_WDT_CNT_STEP; u32 prtmr_step = pretimeout * SPRD_WDT_CNT_STEP;
/*
* Checking busy bit to make sure the previous loading operation is
* done. According to the specification, the busy bit would be set
* after a new loading operation and last 2 or 3 RTC clock
* cycles (about 60us~92us).
*/
do {
val = readl_relaxed(wdt->base + SPRD_WDT_INT_RAW);
if (!(val & SPRD_WDT_LD_BUSY_BIT))
break;
usleep_range(10, 100);
} while (delay_cnt++ < SPRD_WDT_LOAD_TIMEOUT);
if (delay_cnt >= SPRD_WDT_LOAD_TIMEOUT)
return -EBUSY;
sprd_wdt_unlock(wdt->base); sprd_wdt_unlock(wdt->base);
writel_relaxed((tmr_step >> SPRD_WDT_CNT_HIGH_SHIFT) & writel_relaxed((tmr_step >> SPRD_WDT_CNT_HIGH_SHIFT) &
SPRD_WDT_LOW_VALUE_MASK, wdt->base + SPRD_WDT_LOAD_HIGH); SPRD_WDT_LOW_VALUE_MASK, wdt->base + SPRD_WDT_LOAD_HIGH);
...@@ -120,20 +138,6 @@ static int sprd_wdt_load_value(struct sprd_wdt *wdt, u32 timeout, ...@@ -120,20 +138,6 @@ static int sprd_wdt_load_value(struct sprd_wdt *wdt, u32 timeout,
wdt->base + SPRD_WDT_IRQ_LOAD_LOW); wdt->base + SPRD_WDT_IRQ_LOAD_LOW);
sprd_wdt_lock(wdt->base); sprd_wdt_lock(wdt->base);
/*
* Waiting the load value operation done,
* it needs two or three RTC clock cycles.
*/
do {
val = readl_relaxed(wdt->base + SPRD_WDT_INT_RAW);
if (!(val & SPRD_WDT_LD_BUSY_BIT))
break;
cpu_relax();
} while (delay_cnt++ < SPRD_WDT_LOAD_TIMEOUT);
if (delay_cnt >= SPRD_WDT_LOAD_TIMEOUT)
return -EBUSY;
return 0; return 0;
} }
...@@ -345,15 +349,10 @@ static int __maybe_unused sprd_wdt_pm_resume(struct device *dev) ...@@ -345,15 +349,10 @@ static int __maybe_unused sprd_wdt_pm_resume(struct device *dev)
if (ret) if (ret)
return ret; return ret;
if (watchdog_active(&wdt->wdd)) { if (watchdog_active(&wdt->wdd))
ret = sprd_wdt_start(&wdt->wdd); ret = sprd_wdt_start(&wdt->wdd);
if (ret) {
sprd_wdt_disable(wdt);
return ret;
}
}
return 0; return ret;
} }
static const struct dev_pm_ops sprd_wdt_pm_ops = { static const struct dev_pm_ops sprd_wdt_pm_ops = {
......
...@@ -162,18 +162,15 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, ...@@ -162,18 +162,15 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev,
u32 ret; u32 ret;
wdt->clk_lsi = devm_clk_get(dev, "lsi"); wdt->clk_lsi = devm_clk_get(dev, "lsi");
if (IS_ERR(wdt->clk_lsi)) { if (IS_ERR(wdt->clk_lsi))
dev_err(dev, "Unable to get lsi clock\n"); return dev_err_probe(dev, PTR_ERR(wdt->clk_lsi), "Unable to get lsi clock\n");
return PTR_ERR(wdt->clk_lsi);
}
/* optional peripheral clock */ /* optional peripheral clock */
if (wdt->data->has_pclk) { if (wdt->data->has_pclk) {
wdt->clk_pclk = devm_clk_get(dev, "pclk"); wdt->clk_pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(wdt->clk_pclk)) { if (IS_ERR(wdt->clk_pclk))
dev_err(dev, "Unable to get pclk clock\n"); return dev_err_probe(dev, PTR_ERR(wdt->clk_pclk),
return PTR_ERR(wdt->clk_pclk); "Unable to get pclk clock\n");
}
ret = clk_prepare_enable(wdt->clk_pclk); ret = clk_prepare_enable(wdt->clk_pclk);
if (ret) { if (ret) {
......
...@@ -267,15 +267,19 @@ static int __watchdog_register_device(struct watchdog_device *wdd) ...@@ -267,15 +267,19 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
} }
if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) { if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
wdd->reboot_nb.notifier_call = watchdog_reboot_notifier; if (!wdd->ops->stop)
pr_warn("watchdog%d: stop_on_reboot not supported\n", wdd->id);
ret = register_reboot_notifier(&wdd->reboot_nb); else {
if (ret) { wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
wdd->id, ret); ret = register_reboot_notifier(&wdd->reboot_nb);
watchdog_dev_unregister(wdd); if (ret) {
ida_simple_remove(&watchdog_ida, id); pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
return ret; wdd->id, ret);
watchdog_dev_unregister(wdd);
ida_simple_remove(&watchdog_ida, id);
return ret;
}
} }
} }
......
...@@ -34,9 +34,9 @@ struct wdat_instruction { ...@@ -34,9 +34,9 @@ struct wdat_instruction {
* @period: How long is one watchdog period in ms * @period: How long is one watchdog period in ms
* @stopped_in_sleep: Is this watchdog stopped by the firmware in S1-S5 * @stopped_in_sleep: Is this watchdog stopped by the firmware in S1-S5
* @stopped: Was the watchdog stopped by the driver in suspend * @stopped: Was the watchdog stopped by the driver in suspend
* @actions: An array of instruction lists indexed by an action number from * @instructions: An array of instruction lists indexed by an action number from
* the WDAT table. There can be %NULL entries for not implemented * the WDAT table. There can be %NULL entries for not implemented
* actions. * actions.
*/ */
struct wdat_wdt { struct wdat_wdt {
struct platform_device *pdev; struct platform_device *pdev;
......
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