linux-watchdog 5.11-rc1 tag

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.14 (GNU/Linux)
 
 iEYEABECAAYFAl/jfRcACgkQ+iyteGJfRspXnQCfYAyqptMHDHGC98z5kFpsIcxg
 R6MAmQG3jN5aUiwrKcGG2NxQlEGeGVLq
 =bHWM
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2020-12-23 15:01:49 -08:00
commit 6755f45631
17 changed files with 103 additions and 369 deletions

View file

@ -21,6 +21,9 @@ properties:
- items:
- const: allwinner,sun50i-a64-wdt
- const: allwinner,sun6i-a31-wdt
- items:
- const: allwinner,sun50i-a100-wdt
- const: allwinner,sun6i-a31-wdt
- items:
- const: allwinner,sun50i-h6-wdt
- const: allwinner,sun6i-a31-wdt

View file

@ -14,7 +14,15 @@ maintainers:
properties:
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:
maxItems: 1

View file

@ -386,6 +386,7 @@ config ARM_SBSA_WATCHDOG
config ARMADA_37XX_WATCHDOG
tristate "Armada 37xx watchdog"
depends on ARCH_MVEBU || COMPILE_TEST
depends on HAS_IOMEM
select MFD_SYSCON
select WATCHDOG_CORE
help
@ -631,7 +632,7 @@ config SUNXI_WATCHDOG
config COH901327_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
select WATCHDOG_CORE
help
@ -789,6 +790,7 @@ config MOXART_WDT
config SIRFSOC_WATCHDOG
tristate "SiRFSOC watchdog"
depends on HAS_IOMEM
depends on ARCH_SIRF || COMPILE_TEST
select WATCHDOG_CORE
default y
@ -1696,16 +1698,6 @@ config WDT_MTX1
Hardware driver for the MTX-1 boards. This is a watchdog timer that
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
tristate "Sibyte SoC hardware watchdog"
depends on CPU_SB1 || (MIPS && COMPILE_TEST)

View file

@ -161,7 +161,6 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_JZ4740_WDT) += jz4740_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_AR7_WDT) += ar7_wdt.o
obj-$(CONFIG_TXX9_WDT) += txx9wdt.o

View file

@ -150,8 +150,6 @@ static long geodewdt_ioctl(struct file *file, unsigned int cmd,
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);

View file

@ -21,8 +21,9 @@
#include <linux/types.h>
#include <linux/watchdog.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 TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TICKS 65535
@ -334,6 +335,11 @@ static int hpwdt_init_one(struct pci_dev *dev,
watchdog_set_nowayout(&hpwdt_dev, nowayout);
watchdog_init_timeout(&hpwdt_dev, soft_margin, NULL);
if (is_kdump_kernel()) {
pretimeout = 0;
kdumptimeout = 0;
}
if (pretimeout && hpwdt_dev.timeout <= PRETIMEOUT_SEC) {
dev_warn(&dev->dev, "timeout <= pretimeout. Setting pretimeout to zero\n");
pretimeout = 0;

View file

@ -40,8 +40,6 @@
* Includes, defines, variables, module parameters, ...
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.11"
@ -279,7 +277,7 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev)
/* disable chipset's NO_REBOOT bit */
if (p->update_no_reboot_bit(p->no_reboot_priv, false)) {
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;
}
@ -510,7 +508,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
/* Check chipset's NO_REBOOT bit */
if (p->update_no_reboot_bit(p->no_reboot_priv, false) &&
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 */
}
@ -530,12 +528,12 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
if (!devm_request_region(dev, p->tco_res->start,
resource_size(p->tco_res),
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));
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));
/* Clear out the (probably old) status */
@ -558,7 +556,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
break;
}
p->wddev.info = &ident,
p->wddev.info = &ident,
p->wddev.ops = &iTCO_wdt_ops,
p->wddev.bootstatus = 0;
p->wddev.timeout = WATCHDOG_TIMEOUT;
@ -575,7 +573,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
if not reset to the default */
if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) {
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);
}
@ -583,11 +581,11 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
watchdog_stop_on_unregister(&p->wddev);
ret = devm_watchdog_register_device(dev, &p->wddev);
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;
}
pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
dev_info(dev, "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
return 0;
@ -651,21 +649,7 @@ static struct platform_driver iTCO_wdt_driver = {
},
};
static int __init iTCO_wdt_init_module(void)
{
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_platform_driver(iTCO_wdt_driver);
MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");

View file

@ -175,8 +175,8 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
spin_lock_init(&ddata->lock);
ddata->wdd.info = &mpc8xxx_wdt_info,
ddata->wdd.ops = &mpc8xxx_wdt_ops,
ddata->wdd.info = &mpc8xxx_wdt_info;
ddata->wdd.ops = &mpc8xxx_wdt_ops;
ddata->wdd.timeout = WATCHDOG_TIMEOUT;
watchdog_init_timeout(&ddata->wdd, timeout, dev);

View file

@ -1,277 +0,0 @@
// 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");

View file

@ -148,10 +148,17 @@ static int qcom_wdt_restart(struct watchdog_device *wdd, unsigned long action,
*/
wmb();
msleep(150);
mdelay(150);
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 = {
.start = qcom_wdt_start,
.stop = qcom_wdt_stop,
@ -294,6 +301,17 @@ static int qcom_wdt_probe(struct platform_device *pdev)
wdt->wdd.timeout = min(wdt->wdd.max_timeout, 30U);
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);
if (ret)
return ret;

View file

@ -227,8 +227,10 @@ static int rti_wdt_probe(struct platform_device *pdev)
pm_runtime_enable(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");
}
platform_set_drvdata(pdev, wdt);

View file

@ -78,7 +78,7 @@ static int fitpc2_wdt_open(struct inode *inode, struct file *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 i;
@ -125,16 +125,16 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
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;
break;
case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg);
ret = put_user(0, (int __user *)arg);
break;
case WDIOC_GETBOOTSTATUS:
ret = put_user(0, (int *)arg);
ret = put_user(0, (int __user *)arg);
break;
case WDIOC_KEEPALIVE:
@ -143,7 +143,7 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd,
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
ret = get_user(time, (int __user *)arg);
if (ret)
break;
@ -157,7 +157,7 @@ static long fitpc2_wdt_ioctl(struct file *file, unsigned int cmd,
fallthrough;
case WDIOC_GETTIMEOUT:
ret = put_user(margin, (int *)arg);
ret = put_user(margin, (int __user *)arg);
break;
}

View file

@ -291,6 +291,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
}
watchdog_stop_on_reboot(&wdt->wdd);
ret = watchdog_register_device(&wdt->wdd);
if (ret)
goto err;

View file

@ -6,6 +6,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/interrupt.h>
@ -53,7 +54,7 @@
#define SPRD_WDT_CNT_HIGH_SHIFT 16
#define SPRD_WDT_LOW_VALUE_MASK GENMASK(15, 0)
#define SPRD_WDT_LOAD_TIMEOUT 1000
#define SPRD_WDT_LOAD_TIMEOUT 11
struct sprd_wdt {
void __iomem *base;
@ -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 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);
writel_relaxed((tmr_step >> SPRD_WDT_CNT_HIGH_SHIFT) &
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,
wdt->base + SPRD_WDT_IRQ_LOAD_LOW);
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;
}
@ -345,15 +349,10 @@ static int __maybe_unused sprd_wdt_pm_resume(struct device *dev)
if (ret)
return ret;
if (watchdog_active(&wdt->wdd)) {
if (watchdog_active(&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 = {

View file

@ -162,18 +162,15 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev,
u32 ret;
wdt->clk_lsi = devm_clk_get(dev, "lsi");
if (IS_ERR(wdt->clk_lsi)) {
dev_err(dev, "Unable to get lsi clock\n");
return PTR_ERR(wdt->clk_lsi);
}
if (IS_ERR(wdt->clk_lsi))
return dev_err_probe(dev, PTR_ERR(wdt->clk_lsi), "Unable to get lsi clock\n");
/* optional peripheral clock */
if (wdt->data->has_pclk) {
wdt->clk_pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(wdt->clk_pclk)) {
dev_err(dev, "Unable to get pclk clock\n");
return PTR_ERR(wdt->clk_pclk);
}
if (IS_ERR(wdt->clk_pclk))
return dev_err_probe(dev, PTR_ERR(wdt->clk_pclk),
"Unable to get pclk clock\n");
ret = clk_prepare_enable(wdt->clk_pclk);
if (ret) {

View file

@ -267,15 +267,19 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
}
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);
else {
wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
ret = register_reboot_notifier(&wdd->reboot_nb);
if (ret) {
pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
wdd->id, ret);
watchdog_dev_unregister(wdd);
ida_simple_remove(&watchdog_ida, id);
return ret;
ret = register_reboot_notifier(&wdd->reboot_nb);
if (ret) {
pr_err("watchdog%d: Cannot register reboot notifier (%d)\n",
wdd->id, ret);
watchdog_dev_unregister(wdd);
ida_simple_remove(&watchdog_ida, id);
return ret;
}
}
}

View file

@ -34,9 +34,9 @@ struct wdat_instruction {
* @period: How long is one watchdog period in ms
* @stopped_in_sleep: Is this watchdog stopped by the firmware in S1-S5
* @stopped: Was the watchdog stopped by the driver in suspend
* @actions: An array of instruction lists indexed by an action number from
* the WDAT table. There can be %NULL entries for not implemented
* actions.
* @instructions: An array of instruction lists indexed by an action number from
* the WDAT table. There can be %NULL entries for not implemented
* actions.
*/
struct wdat_wdt {
struct platform_device *pdev;