linux-watchdog 5.15-rc1 tag

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.14 (GNU/Linux)
 
 iEYEABECAAYFAmE3t2UACgkQ+iyteGJfRspKrgCfVDZuMeFiDrRjPz9FMDUncIZ7
 /24AoKWWPcOJLNXXNCwwD61kcW34LzVV
 =gMcs
 -----END PGP SIGNATURE-----

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

Pull watchdog updates from Wim Van Sebroeck:

 - add Mediatek MT7986 & MT8195 wdt support

 - add Maxim MAX63xx

 - drop bd70528 support

 - rewrite ixp4xx to watchdog framework

 - constify static struct watchdog_ops for sl28cpld_wdt, mpc8xxx_wdt and
   tqmx86

 - introduce watchdog_dev_suspend/resume

 - several fixes and improvements

* tag 'linux-watchdog-5.15-rc1' of git://www.linux-watchdog.org/linux-watchdog:
  dt-bindings: watchdog: Add compatible for Mediatek MT7986
  watchdog: ixp4xx: Rewrite driver to use core
  watchdog: Start watchdog in watchdog_set_last_hw_keepalive only if appropriate
  watchdog: max63xx_wdt: Add device tree probing
  dt-bindings: watchdog: Add Maxim MAX63xx bindings
  watchdog: mediatek: mt8195: add wdt support
  dt-bindings: reset: mt8195: add toprgu reset-controller header file
  watchdog: tqmx86: Constify static struct watchdog_ops
  watchdog: mpc8xxx_wdt: Constify static struct watchdog_ops
  watchdog: sl28cpld_wdt: Constify static struct watchdog_ops
  watchdog: iTCO_wdt: Fix detection of SMI-off case
  watchdog: bcm2835_wdt: consider system-power-controller property
  watchdog: imx2_wdg: notify wdog core to stop ping worker on suspend
  watchdog: introduce watchdog_dev_suspend/resume
  watchdog: Fix NULL pointer dereference when releasing cdev
  watchdog: only run driver set_pretimeout op if device supports it
  watchdog: bd70528 drop bd70528 support
This commit is contained in:
Linus Torvalds 2021-09-07 13:52:46 -07:00
commit 4c00e1e2e5
17 changed files with 213 additions and 318 deletions

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/watchdog/maxim,max63xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim 63xx Watchdog Timers
allOf:
- $ref: "watchdog.yaml#"
maintainers:
- Marc Zyngier <maz@kernel.org>
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
oneOf:
- const: maxim,max6369
- const: maxim,max6370
- const: maxim,max6371
- const: maxim,max6372
- const: maxim,max6373
- const: maxim,max6374
reg:
description: This is a 1-byte memory-mapped address
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
wdt: watchdog@50000000 {
compatible = "maxim,max6369";
reg = <0x50000000 0x1>;
timeout-sec = <10>;
};
...

View File

@ -13,6 +13,7 @@ Required properties:
"mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622
"mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623
"mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
"mediatek,mt7986-wdt", "mediatek,mt6589-wdt": for MT7986
"mediatek,mt8183-wdt": for MT8183
"mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516
"mediatek,mt8192-wdt": for MT8192

View File

@ -168,18 +168,6 @@ config SOFT_WATCHDOG_PRETIMEOUT
watchdog. Be aware that governors might affect the watchdog because it
is purely software, e.g. the panic governor will stall it!
config BD70528_WATCHDOG
tristate "ROHM BD70528 PMIC Watchdog"
depends on MFD_ROHM_BD70528
select WATCHDOG_CORE
help
Support for the watchdog in the ROHM BD70528 PMIC. Watchdog trigger
cause system reset.
Say Y here to include support for the ROHM BD70528 watchdog.
Alternatively say M to compile the driver as a module,
which will be called bd70528_wdt.
config BD957XMUF_WATCHDOG
tristate "ROHM BD9576MUF and BD9573MUF PMIC Watchdog"
depends on MFD_ROHM_BD957XMUF

View File

@ -204,7 +204,6 @@ obj-$(CONFIG_WATCHDOG_SUN4V) += sun4v_wdt.o
obj-$(CONFIG_XEN_WDT) += xen_wdt.o
# Architecture Independent
obj-$(CONFIG_BD70528_WATCHDOG) += bd70528_wdt.o
obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o
obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o

View File

@ -205,9 +205,13 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
if (err)
return err;
if (pm_power_off == NULL) {
pm_power_off = bcm2835_power_off;
bcm2835_power_off_wdt = wdt;
if (of_device_is_system_power_controller(pdev->dev.parent->of_node)) {
if (!pm_power_off) {
pm_power_off = bcm2835_power_off;
bcm2835_power_off_wdt = wdt;
} else {
dev_info(dev, "Poweroff handler already present!\n");
}
}
dev_info(dev, "Broadcom BCM2835 watchdog timer");

View File

@ -1,291 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 ROHM Semiconductors
// ROHM BD70528MWV watchdog driver
#include <linux/bcd.h>
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd70528.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/watchdog.h>
/*
* Max time we can set is 1 hour, 59 minutes and 59 seconds
* and Minimum time is 1 second
*/
#define WDT_MAX_MS ((2 * 60 * 60 - 1) * 1000)
#define WDT_MIN_MS 1000
#define DEFAULT_TIMEOUT 60
#define WD_CTRL_MAGIC1 0x55
#define WD_CTRL_MAGIC2 0xAA
struct wdtbd70528 {
struct device *dev;
struct regmap *regmap;
struct rohm_regmap_dev *mfd;
struct watchdog_device wdt;
};
/**
* bd70528_wdt_set - arm or disarm watchdog timer
*
* @data: device data for the PMIC instance we want to operate on
* @enable: new state of WDT. zero to disable, non zero to enable
* @old_state: previous state of WDT will be filled here
*
* Arm or disarm WDT on BD70528 PMIC. Expected to be called only by
* BD70528 RTC and BD70528 WDT drivers. The rtc_timer_lock must be taken
* by calling bd70528_wdt_lock before calling bd70528_wdt_set.
*/
int bd70528_wdt_set(struct rohm_regmap_dev *data, int enable, int *old_state)
{
int ret, i;
unsigned int tmp;
struct bd70528_data *bd70528 = container_of(data, struct bd70528_data,
chip);
u8 wd_ctrl_arr[3] = { WD_CTRL_MAGIC1, WD_CTRL_MAGIC2, 0 };
u8 *wd_ctrl = &wd_ctrl_arr[2];
ret = regmap_read(bd70528->chip.regmap, BD70528_REG_WDT_CTRL, &tmp);
if (ret)
return ret;
*wd_ctrl = (u8)tmp;
if (old_state) {
if (*wd_ctrl & BD70528_MASK_WDT_EN)
*old_state |= BD70528_WDT_STATE_BIT;
else
*old_state &= ~BD70528_WDT_STATE_BIT;
if ((!enable) == (!(*old_state & BD70528_WDT_STATE_BIT)))
return 0;
}
if (enable) {
if (*wd_ctrl & BD70528_MASK_WDT_EN)
return 0;
*wd_ctrl |= BD70528_MASK_WDT_EN;
} else {
if (*wd_ctrl & BD70528_MASK_WDT_EN)
*wd_ctrl &= ~BD70528_MASK_WDT_EN;
else
return 0;
}
for (i = 0; i < 3; i++) {
ret = regmap_write(bd70528->chip.regmap, BD70528_REG_WDT_CTRL,
wd_ctrl_arr[i]);
if (ret)
return ret;
}
ret = regmap_read(bd70528->chip.regmap, BD70528_REG_WDT_CTRL, &tmp);
if ((tmp & BD70528_MASK_WDT_EN) != (*wd_ctrl & BD70528_MASK_WDT_EN)) {
dev_err(bd70528->chip.dev,
"Watchdog ctrl mismatch (hw) 0x%x (set) 0x%x\n",
tmp, *wd_ctrl);
ret = -EIO;
}
return ret;
}
EXPORT_SYMBOL(bd70528_wdt_set);
/**
* bd70528_wdt_lock - take WDT lock
*
* @data: device data for the PMIC instance we want to operate on
*
* Lock WDT for arming/disarming in order to avoid race condition caused
* by WDT state changes initiated by WDT and RTC drivers.
*/
void bd70528_wdt_lock(struct rohm_regmap_dev *data)
{
struct bd70528_data *bd70528 = container_of(data, struct bd70528_data,
chip);
mutex_lock(&bd70528->rtc_timer_lock);
}
EXPORT_SYMBOL(bd70528_wdt_lock);
/**
* bd70528_wdt_unlock - unlock WDT lock
*
* @data: device data for the PMIC instance we want to operate on
*
* Unlock WDT lock which has previously been taken by call to
* bd70528_wdt_lock.
*/
void bd70528_wdt_unlock(struct rohm_regmap_dev *data)
{
struct bd70528_data *bd70528 = container_of(data, struct bd70528_data,
chip);
mutex_unlock(&bd70528->rtc_timer_lock);
}
EXPORT_SYMBOL(bd70528_wdt_unlock);
static int bd70528_wdt_set_locked(struct wdtbd70528 *w, int enable)
{
return bd70528_wdt_set(w->mfd, enable, NULL);
}
static int bd70528_wdt_change(struct wdtbd70528 *w, int enable)
{
int ret;
bd70528_wdt_lock(w->mfd);
ret = bd70528_wdt_set_locked(w, enable);
bd70528_wdt_unlock(w->mfd);
return ret;
}
static int bd70528_wdt_start(struct watchdog_device *wdt)
{
struct wdtbd70528 *w = watchdog_get_drvdata(wdt);
dev_dbg(w->dev, "WDT ping...\n");
return bd70528_wdt_change(w, 1);
}
static int bd70528_wdt_stop(struct watchdog_device *wdt)
{
struct wdtbd70528 *w = watchdog_get_drvdata(wdt);
dev_dbg(w->dev, "WDT stopping...\n");
return bd70528_wdt_change(w, 0);
}
static int bd70528_wdt_set_timeout(struct watchdog_device *wdt,
unsigned int timeout)
{
unsigned int hours;
unsigned int minutes;
unsigned int seconds;
int ret;
struct wdtbd70528 *w = watchdog_get_drvdata(wdt);
seconds = timeout;
hours = timeout / (60 * 60);
/* Maximum timeout is 1h 59m 59s => hours is 1 or 0 */
if (hours)
seconds -= (60 * 60);
minutes = seconds / 60;
seconds = seconds % 60;
bd70528_wdt_lock(w->mfd);
ret = bd70528_wdt_set_locked(w, 0);
if (ret)
goto out_unlock;
ret = regmap_update_bits(w->regmap, BD70528_REG_WDT_HOUR,
BD70528_MASK_WDT_HOUR, hours);
if (ret) {
dev_err(w->dev, "Failed to set WDT hours\n");
goto out_en_unlock;
}
ret = regmap_update_bits(w->regmap, BD70528_REG_WDT_MINUTE,
BD70528_MASK_WDT_MINUTE, bin2bcd(minutes));
if (ret) {
dev_err(w->dev, "Failed to set WDT minutes\n");
goto out_en_unlock;
}
ret = regmap_update_bits(w->regmap, BD70528_REG_WDT_SEC,
BD70528_MASK_WDT_SEC, bin2bcd(seconds));
if (ret)
dev_err(w->dev, "Failed to set WDT seconds\n");
else
dev_dbg(w->dev, "WDT tmo set to %u\n", timeout);
out_en_unlock:
ret = bd70528_wdt_set_locked(w, 1);
out_unlock:
bd70528_wdt_unlock(w->mfd);
return ret;
}
static const struct watchdog_info bd70528_wdt_info = {
.identity = "bd70528-wdt",
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
};
static const struct watchdog_ops bd70528_wdt_ops = {
.start = bd70528_wdt_start,
.stop = bd70528_wdt_stop,
.set_timeout = bd70528_wdt_set_timeout,
};
static int bd70528_wdt_probe(struct platform_device *pdev)
{
struct rohm_regmap_dev *bd70528;
struct wdtbd70528 *w;
int ret;
unsigned int reg;
bd70528 = dev_get_drvdata(pdev->dev.parent);
if (!bd70528) {
dev_err(&pdev->dev, "No MFD driver data\n");
return -EINVAL;
}
w = devm_kzalloc(&pdev->dev, sizeof(*w), GFP_KERNEL);
if (!w)
return -ENOMEM;
w->regmap = bd70528->regmap;
w->mfd = bd70528;
w->dev = &pdev->dev;
w->wdt.info = &bd70528_wdt_info;
w->wdt.ops = &bd70528_wdt_ops;
w->wdt.min_hw_heartbeat_ms = WDT_MIN_MS;
w->wdt.max_hw_heartbeat_ms = WDT_MAX_MS;
w->wdt.parent = pdev->dev.parent;
w->wdt.timeout = DEFAULT_TIMEOUT;
watchdog_set_drvdata(&w->wdt, w);
watchdog_init_timeout(&w->wdt, 0, pdev->dev.parent);
ret = bd70528_wdt_set_timeout(&w->wdt, w->wdt.timeout);
if (ret) {
dev_err(&pdev->dev, "Failed to set the watchdog timeout\n");
return ret;
}
bd70528_wdt_lock(w->mfd);
ret = regmap_read(w->regmap, BD70528_REG_WDT_CTRL, &reg);
bd70528_wdt_unlock(w->mfd);
if (ret) {
dev_err(&pdev->dev, "Failed to get the watchdog state\n");
return ret;
}
if (reg & BD70528_MASK_WDT_EN) {
dev_dbg(&pdev->dev, "watchdog was running during probe\n");
set_bit(WDOG_HW_RUNNING, &w->wdt.status);
}
ret = devm_watchdog_register_device(&pdev->dev, &w->wdt);
if (ret < 0)
dev_err(&pdev->dev, "watchdog registration failed: %d\n", ret);
return ret;
}
static struct platform_driver bd70528_wdt = {
.driver = {
.name = "bd70528-wdt"
},
.probe = bd70528_wdt_probe,
};
module_platform_driver(bd70528_wdt);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD70528 watchdog driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd70528-wdt");

View File

@ -362,7 +362,7 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
* Otherwise, the BIOS generally reboots when the SMI triggers.
*/
if (p->smi_res &&
(SMI_EN(p) & (TCO_EN | GBL_SMI_EN)) != (TCO_EN | GBL_SMI_EN))
(inl(SMI_EN(p)) & (TCO_EN | GBL_SMI_EN)) != (TCO_EN | GBL_SMI_EN))
tmrval /= 2;
/* from the specs: */

View File

@ -317,6 +317,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
watchdog_set_nowayout(wdog, nowayout);
watchdog_set_restart_priority(wdog, 128);
watchdog_init_timeout(wdog, timeout, dev);
watchdog_stop_ping_on_suspend(wdog);
if (imx2_wdt_is_running(wdev)) {
imx2_wdt_set_timeout(wdog, wdog->timeout);

View File

@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/property.h>
#define DEFAULT_HEARTBEAT 60
#define MAX_HEARTBEAT 60
@ -99,8 +100,8 @@ static const struct max63xx_timeout max6373_table[] = {
{ },
};
static struct max63xx_timeout *
max63xx_select_timeout(struct max63xx_timeout *table, int value)
static const struct max63xx_timeout *
max63xx_select_timeout(const struct max63xx_timeout *table, int value)
{
while (table->twd) {
if (value <= table->twd) {
@ -202,14 +203,17 @@ static int max63xx_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct max63xx_wdt *wdt;
struct max63xx_timeout *table;
const struct max63xx_timeout *table;
int err;
wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt)
return -ENOMEM;
table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
/* Attempt to use fwnode first */
table = device_get_match_data(dev);
if (!table)
table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
@ -255,11 +259,23 @@ static const struct platform_device_id max63xx_id_table[] = {
};
MODULE_DEVICE_TABLE(platform, max63xx_id_table);
static const struct of_device_id max63xx_dt_id_table[] = {
{ .compatible = "maxim,max6369", .data = max6369_table, },
{ .compatible = "maxim,max6370", .data = max6369_table, },
{ .compatible = "maxim,max6371", .data = max6371_table, },
{ .compatible = "maxim,max6372", .data = max6371_table, },
{ .compatible = "maxim,max6373", .data = max6373_table, },
{ .compatible = "maxim,max6374", .data = max6373_table, },
{ }
};
MODULE_DEVICE_TABLE(of, max63xx_dt_id_table);
static struct platform_driver max63xx_wdt_driver = {
.probe = max63xx_wdt_probe,
.id_table = max63xx_id_table,
.driver = {
.name = "max63xx_wdt",
.of_match_table = max63xx_dt_id_table,
},
};

View File

@ -118,7 +118,7 @@ static struct watchdog_info mpc8xxx_wdt_info = {
.identity = "MPC8xxx",
};
static struct watchdog_ops mpc8xxx_wdt_ops = {
static const struct watchdog_ops mpc8xxx_wdt_ops = {
.owner = THIS_MODULE,
.start = mpc8xxx_wdt_start,
.ping = mpc8xxx_wdt_ping,

View File

@ -12,6 +12,7 @@
#include <dt-bindings/reset-controller/mt2712-resets.h>
#include <dt-bindings/reset-controller/mt8183-resets.h>
#include <dt-bindings/reset-controller/mt8192-resets.h>
#include <dt-bindings/reset/mt8195-resets.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
@ -82,6 +83,10 @@ static const struct mtk_wdt_data mt8192_data = {
.toprgu_sw_rst_num = MT8192_TOPRGU_SW_RST_NUM,
};
static const struct mtk_wdt_data mt8195_data = {
.toprgu_sw_rst_num = MT8195_TOPRGU_SW_RST_NUM,
};
static int toprgu_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
@ -408,6 +413,7 @@ static const struct of_device_id mtk_wdt_dt_ids[] = {
{ .compatible = "mediatek,mt6589-wdt" },
{ .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },
{ .compatible = "mediatek,mt8192-wdt", .data = &mt8192_data },
{ .compatible = "mediatek,mt8195-wdt", .data = &mt8195_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);

View File

@ -108,7 +108,7 @@ static const struct watchdog_info sl28cpld_wdt_info = {
.identity = "sl28cpld watchdog",
};
static struct watchdog_ops sl28cpld_wdt_ops = {
static const struct watchdog_ops sl28cpld_wdt_ops = {
.owner = THIS_MODULE,
.start = sl28cpld_wdt_start,
.stop = sl28cpld_wdt_stop,

View File

@ -62,7 +62,7 @@ static const struct watchdog_info tqmx86_wdt_info = {
.identity = "TQMx86 Watchdog",
};
static struct watchdog_ops tqmx86_wdt_ops = {
static const struct watchdog_ops tqmx86_wdt_ops = {
.owner = THIS_MODULE,
.start = tqmx86_wdt_start,
.set_timeout = tqmx86_wdt_set_timeout,

View File

@ -34,6 +34,7 @@
#include <linux/idr.h> /* For ida_* macros */
#include <linux/err.h> /* For IS_ERR macros */
#include <linux/of.h> /* For of_get_timeout_sec */
#include <linux/suspend.h>
#include "watchdog_core.h" /* For watchdog_dev_register/... */
@ -185,6 +186,33 @@ static int watchdog_restart_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
}
static int watchdog_pm_notifier(struct notifier_block *nb, unsigned long mode,
void *data)
{
struct watchdog_device *wdd;
int ret = 0;
wdd = container_of(nb, struct watchdog_device, pm_nb);
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_RESTORE_PREPARE:
case PM_SUSPEND_PREPARE:
ret = watchdog_dev_suspend(wdd);
break;
case PM_POST_HIBERNATION:
case PM_POST_RESTORE:
case PM_POST_SUSPEND:
ret = watchdog_dev_resume(wdd);
break;
}
if (ret)
return NOTIFY_BAD;
return NOTIFY_DONE;
}
/**
* watchdog_set_restart_priority - Change priority of restart handler
* @wdd: watchdog device
@ -292,6 +320,15 @@ static int __watchdog_register_device(struct watchdog_device *wdd)
wdd->id, ret);
}
if (test_bit(WDOG_NO_PING_ON_SUSPEND, &wdd->status)) {
wdd->pm_nb.notifier_call = watchdog_pm_notifier;
ret = register_pm_notifier(&wdd->pm_nb);
if (ret)
pr_warn("watchdog%d: Cannot register pm handler (%d)\n",
wdd->id, ret);
}
return 0;
}

View File

@ -401,7 +401,7 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd,
if (watchdog_pretimeout_invalid(wdd, timeout))
return -EINVAL;
if (wdd->ops->set_pretimeout)
if (wdd->ops->set_pretimeout && (wdd->info->options & WDIOF_PRETIMEOUT))
err = wdd->ops->set_pretimeout(wdd, timeout);
else
wdd->pretimeout = timeout;
@ -1096,6 +1096,8 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
watchdog_stop(wdd);
}
watchdog_hrtimer_pretimeout_stop(wdd);
mutex_lock(&wd_data->lock);
wd_data->wdd = NULL;
wdd->wd_data = NULL;
@ -1103,7 +1105,6 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
hrtimer_cancel(&wd_data->timer);
kthread_cancel_work_sync(&wd_data->work);
watchdog_hrtimer_pretimeout_stop(wdd);
put_device(&wd_data->dev);
}
@ -1172,7 +1173,10 @@ int watchdog_set_last_hw_keepalive(struct watchdog_device *wdd,
wd_data->last_hw_keepalive = ktime_sub(now, ms_to_ktime(last_ping_ms));
return __watchdog_ping(wdd);
if (watchdog_hw_running(wdd) && handle_boot_enabled)
return __watchdog_ping(wdd);
return 0;
}
EXPORT_SYMBOL_GPL(watchdog_set_last_hw_keepalive);
@ -1227,6 +1231,53 @@ void __exit watchdog_dev_exit(void)
kthread_destroy_worker(watchdog_kworker);
}
int watchdog_dev_suspend(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data = wdd->wd_data;
int ret = 0;
if (!wdd->wd_data)
return -ENODEV;
/* ping for the last time before suspend */
mutex_lock(&wd_data->lock);
if (watchdog_worker_should_ping(wd_data))
ret = __watchdog_ping(wd_data->wdd);
mutex_unlock(&wd_data->lock);
if (ret)
return ret;
/*
* make sure that watchdog worker will not kick in when the wdog is
* suspended
*/
hrtimer_cancel(&wd_data->timer);
kthread_cancel_work_sync(&wd_data->work);
return 0;
}
int watchdog_dev_resume(struct watchdog_device *wdd)
{
struct watchdog_core_data *wd_data = wdd->wd_data;
int ret = 0;
if (!wdd->wd_data)
return -ENODEV;
/*
* __watchdog_ping will also retrigger hrtimer and therefore restore the
* ping worker if needed.
*/
mutex_lock(&wd_data->lock);
if (watchdog_worker_should_ping(wd_data))
ret = __watchdog_ping(wd_data->wdd);
mutex_unlock(&wd_data->lock);
return ret;
}
module_param(handle_boot_enabled, bool, 0444);
MODULE_PARM_DESC(handle_boot_enabled,
"Watchdog core auto-updates boot enabled watchdogs before userspace takes over (default="

View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)*/
/*
* Copyright (c) 2021 MediaTek Inc.
* Author: Christine Zhu <christine.zhu@mediatek.com>
*/
#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8195
#define _DT_BINDINGS_RESET_CONTROLLER_MT8195
#define MT8195_TOPRGU_CONN_MCU_SW_RST 0
#define MT8195_TOPRGU_INFRA_GRST_SW_RST 1
#define MT8195_TOPRGU_APU_SW_RST 2
#define MT8195_TOPRGU_INFRA_AO_GRST_SW_RST 6
#define MT8195_TOPRGU_MMSYS_SW_RST 7
#define MT8195_TOPRGU_MFG_SW_RST 8
#define MT8195_TOPRGU_VENC_SW_RST 9
#define MT8195_TOPRGU_VDEC_SW_RST 10
#define MT8195_TOPRGU_IMG_SW_RST 11
#define MT8195_TOPRGU_APMIXEDSYS_SW_RST 13
#define MT8195_TOPRGU_AUDIO_SW_RST 14
#define MT8195_TOPRGU_CAMSYS_SW_RST 15
#define MT8195_TOPRGU_EDPTX_SW_RST 16
#define MT8195_TOPRGU_ADSPSYS_SW_RST 21
#define MT8195_TOPRGU_DPTX_SW_RST 22
#define MT8195_TOPRGU_SPMI_MST_SW_RST 23
#define MT8195_TOPRGU_SW_RST_NUM 16
#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT8195 */

View File

@ -107,6 +107,7 @@ struct watchdog_device {
unsigned int max_hw_heartbeat_ms;
struct notifier_block reboot_nb;
struct notifier_block restart_nb;
struct notifier_block pm_nb;
void *driver_data;
struct watchdog_core_data *wd_data;
unsigned long status;
@ -116,6 +117,7 @@ struct watchdog_device {
#define WDOG_STOP_ON_REBOOT 2 /* Should be stopped on reboot */
#define WDOG_HW_RUNNING 3 /* True if HW watchdog running */
#define WDOG_STOP_ON_UNREGISTER 4 /* Should be stopped on unregister */
#define WDOG_NO_PING_ON_SUSPEND 5 /* Ping worker should be stopped on suspend */
struct list_head deferred;
};
@ -156,6 +158,12 @@ static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd)
set_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status);
}
/* Use the following function to stop the wdog ping worker when suspending */
static inline void watchdog_stop_ping_on_suspend(struct watchdog_device *wdd)
{
set_bit(WDOG_NO_PING_ON_SUSPEND, &wdd->status);
}
/* Use the following function to check if a timeout value is invalid */
static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
{
@ -209,6 +217,8 @@ extern int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev);
extern int watchdog_register_device(struct watchdog_device *);
extern void watchdog_unregister_device(struct watchdog_device *);
int watchdog_dev_suspend(struct watchdog_device *wdd);
int watchdog_dev_resume(struct watchdog_device *wdd);
int watchdog_set_last_hw_keepalive(struct watchdog_device *, unsigned int);