summaryrefslogtreecommitdiff
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-01-12 13:32:30 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2024-01-12 13:32:30 -0800
commit61f4c3e6711477b8a347ca5fe89e5e6613e0a147 (patch)
treeca318abb0ad8cb84c2246f0dac97d69c4dafc60b /drivers/watchdog
parent5dfec3cf3efbd897d774e3b5c08c2f0deaf9b5ad (diff)
parent9546b21ea672aa961d5a89ea754214afed013f02 (diff)
Merge tag 'linux-watchdog-6.8-rc1' of git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: - Add Mediatek MT7988 watchdog - Add IT8659 watchdog - watchdog: set cdev owner before adding - hpwdt: Only claim UNKNOWN NMI if from iLO - Various other fixes and improvements * tag 'linux-watchdog-6.8-rc1' of git://www.linux-watchdog.org/linux-watchdog: (30 commits) watchdog: mlx_wdt: fix all kernel-doc warnings dt-bindings: watchdog: qcom,pm8916-wdt: add parent spmi node to example dt-bindings: watchdog: nxp,pnx4008-wdt: convert txt to yaml dt-bindings: watchdog: qca,ar7130-wdt: convert txt to yaml dt-bindings: watchdog: intel,keembay: reference common watchdog schema dt-bindings: watchdog: re-order entries to match coding convention watchdog: it87_wdt: Keep WDTCTRL bit 3 unmodified for IT8784/IT8786 watchdog: it87_wdt: Add IT8659 ID watchdog: it87_wdt: Remove redundant max_units setting watchdog: it87_wdt: add blank line after variable declaration dt-bindings: wdt: Add ts72xx dt-bindings: watchdog: dlg,da9062-watchdog: Document DA9063 watchdog dt-bindings: watchdog: dlg,da9062-watchdog: Add fallback for DA9061 watchdog watchdog: rti_wdt: Drop runtime pm reference count when watchdog is unused watchdog: starfive: add lock annotations to fix context imbalances watchdog: mediatek: mt7988: add wdt support dt-bindings: watchdog: mediatek,mtk-wdt: add MT7988 watchdog and toprgu dt-bindings: watchdog: realtek,rtd1295-watchdog: convert txt to yaml watchdog: bcm2835_wdt: Fix WDIOC_SETTIMEOUT handling watchdog/hpwdt: Remove unused variable ...
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/at91sam9_wdt.c12
-rw-r--r--drivers/watchdog/bcm2835_wdt.c3
-rw-r--r--drivers/watchdog/hpwdt.c9
-rw-r--r--drivers/watchdog/it87_wdt.c29
-rw-r--r--drivers/watchdog/mlx_wdt.c4
-rw-r--r--drivers/watchdog/mtk_wdt.c42
-rw-r--r--drivers/watchdog/rti_wdt.c13
-rw-r--r--drivers/watchdog/starfive-wdt.c8
-rw-r--r--drivers/watchdog/txx9wdt.c11
-rw-r--r--drivers/watchdog/watchdog_dev.c3
10 files changed, 94 insertions, 40 deletions
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index b111b28acb94..2c6474cb858b 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -324,7 +324,7 @@ static inline int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt)
}
#endif
-static int __init at91wdt_probe(struct platform_device *pdev)
+static int at91wdt_probe(struct platform_device *pdev)
{
int err;
struct at91wdt *wdt;
@@ -372,15 +372,13 @@ static int __init at91wdt_probe(struct platform_device *pdev)
return 0;
}
-static int __exit at91wdt_remove(struct platform_device *pdev)
+static void at91wdt_remove(struct platform_device *pdev)
{
struct at91wdt *wdt = platform_get_drvdata(pdev);
watchdog_unregister_device(&wdt->wdd);
pr_warn("I quit now, hardware will probably reboot!\n");
del_timer(&wdt->timer);
-
- return 0;
}
#if defined(CONFIG_OF)
@@ -393,14 +391,14 @@ MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids);
#endif
static struct platform_driver at91wdt_driver = {
- .remove = __exit_p(at91wdt_remove),
+ .probe = at91wdt_probe,
+ .remove_new = at91wdt_remove,
.driver = {
.name = "at91_wdt",
.of_match_table = of_match_ptr(at91_wdt_dt_ids),
},
};
-
-module_platform_driver_probe(at91wdt_driver, at91wdt_probe);
+module_platform_driver(at91wdt_driver);
MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
index 7a855289ff5e..bb001c5d7f17 100644
--- a/drivers/watchdog/bcm2835_wdt.c
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -42,6 +42,7 @@
#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
#define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
+#define WDOG_TICKS_TO_MSECS(x) ((x) * 1000 >> 16)
struct bcm2835_wdt {
void __iomem *base;
@@ -140,7 +141,7 @@ static struct watchdog_device bcm2835_wdt_wdd = {
.info = &bcm2835_wdt_info,
.ops = &bcm2835_wdt_ops,
.min_timeout = 1,
- .max_timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
+ .max_hw_heartbeat_ms = WDOG_TICKS_TO_MSECS(PM_WDOG_TIME_SET),
.timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
};
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index f79f932bca14..138dc8d8ca3d 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -33,7 +33,6 @@
#define DEFAULT_MARGIN 30
#define PRETIMEOUT_SEC 9
-static bool ilo5;
static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */
static bool nowayout = WATCHDOG_NOWAYOUT;
static bool pretimeout = IS_ENABLED(CONFIG_HPWDT_NMI_DECODING);
@@ -178,10 +177,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
"3. OA Forward Progress Log\n"
"4. iLO Event Log";
- if (ilo5 && ulReason == NMI_UNKNOWN && !mynmi)
- return NMI_DONE;
-
- if (ilo5 && !pretimeout && !mynmi)
+ if (ulReason == NMI_UNKNOWN && !mynmi)
return NMI_DONE;
if (kdumptimeout < 0)
@@ -363,9 +359,6 @@ static int hpwdt_init_one(struct pci_dev *dev,
pretimeout ? "on" : "off");
dev_info(&dev->dev, "kdumptimeout: %d.\n", kdumptimeout);
- if (dev->subsystem_vendor == PCI_VENDOR_ID_HP_3PAR)
- ilo5 = true;
-
return 0;
error_wd_register:
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index e888b1bdd1f2..9297a5891912 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -13,9 +13,9 @@
* http://www.ite.com.tw/
*
* Support of the watchdog timers, which are available on
- * IT8607, IT8613, IT8620, IT8622, IT8625, IT8628, IT8655, IT8665,
- * IT8686, IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726,
- * IT8728, IT8772, IT8783 and IT8784.
+ * IT8607, IT8613, IT8620, IT8622, IT8625, IT8628, IT8655, IT8659,
+ * IT8665, IT8686, IT8702, IT8712, IT8716, IT8718, IT8720, IT8721,
+ * IT8726, IT8728, IT8772, IT8783, IT8784 and IT8786.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -56,6 +56,7 @@
#define IT8625_ID 0x8625
#define IT8628_ID 0x8628
#define IT8655_ID 0x8655
+#define IT8659_ID 0x8659
#define IT8665_ID 0x8665
#define IT8686_ID 0x8686
#define IT8702_ID 0x8702
@@ -146,6 +147,7 @@ static inline void superio_outb(int val, int reg)
static inline int superio_inw(int reg)
{
int val;
+
outb(reg++, REG);
val = inb(VAL) << 8;
outb(reg, REG);
@@ -256,6 +258,7 @@ static struct watchdog_device wdt_dev = {
static int __init it87_wdt_init(void)
{
u8 chip_rev;
+ u8 ctrl;
int rc;
rc = superio_enter();
@@ -273,10 +276,6 @@ static int __init it87_wdt_init(void)
case IT8712_ID:
max_units = (chip_rev < 8) ? 255 : 65535;
break;
- case IT8716_ID:
- case IT8726_ID:
- max_units = 65535;
- break;
case IT8607_ID:
case IT8613_ID:
case IT8620_ID:
@@ -284,11 +283,14 @@ static int __init it87_wdt_init(void)
case IT8625_ID:
case IT8628_ID:
case IT8655_ID:
+ case IT8659_ID:
case IT8665_ID:
case IT8686_ID:
+ case IT8716_ID:
case IT8718_ID:
case IT8720_ID:
case IT8721_ID:
+ case IT8726_ID:
case IT8728_ID:
case IT8772_ID:
case IT8783_ID:
@@ -315,7 +317,18 @@ static int __init it87_wdt_init(void)
superio_select(GPIO);
superio_outb(WDT_TOV1, WDTCFG);
- superio_outb(0x00, WDTCTRL);
+
+ switch (chip_type) {
+ case IT8784_ID:
+ case IT8786_ID:
+ ctrl = superio_inb(WDTCTRL);
+ ctrl &= 0x08;
+ superio_outb(ctrl, WDTCTRL);
+ break;
+ default:
+ superio_outb(0x00, WDTCTRL);
+ }
+
superio_exit();
if (timeout < 1 || timeout > max_units * 60) {
diff --git a/drivers/watchdog/mlx_wdt.c b/drivers/watchdog/mlx_wdt.c
index 667e2c5b3431..5dc69363f06a 100644
--- a/drivers/watchdog/mlx_wdt.c
+++ b/drivers/watchdog/mlx_wdt.c
@@ -30,17 +30,15 @@
* struct mlxreg_wdt - wd private data:
*
* @wdd: watchdog device;
- * @device: basic device;
* @pdata: data received from platform driver;
* @regmap: register map of parent device;
- * @timeout: defined timeout in sec.;
* @action_idx: index for direct access to action register;
* @timeout_idx:index for direct access to TO register;
* @tleft_idx: index for direct access to time left register;
* @ping_idx: index for direct access to ping register;
* @reset_idx: index for direct access to reset cause register;
* @regmap_val_sz: size of value in register map;
- * @wd_type: watchdog HW type;
+ * @wdt_type: watchdog HW type;
*/
struct mlxreg_wdt {
struct watchdog_device wdd;
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index b2330b16b497..c35f85ce8d69 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -58,9 +58,13 @@
#define WDT_SWSYSRST 0x18U
#define WDT_SWSYS_RST_KEY 0x88000000
+#define WDT_SWSYSRST_EN 0xfc
+
#define DRV_NAME "mtk-wdt"
#define DRV_VERSION "1.0"
+#define MT7988_TOPRGU_SW_RST_NUM 24
+
static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned int timeout;
@@ -71,10 +75,12 @@ struct mtk_wdt_dev {
struct reset_controller_dev rcdev;
bool disable_wdt_extrst;
bool reset_by_toprgu;
+ bool has_swsysrst_en;
};
struct mtk_wdt_data {
int toprgu_sw_rst_num;
+ bool has_swsysrst_en;
};
static const struct mtk_wdt_data mt2712_data = {
@@ -89,6 +95,11 @@ static const struct mtk_wdt_data mt7986_data = {
.toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM,
};
+static const struct mtk_wdt_data mt7988_data = {
+ .toprgu_sw_rst_num = MT7988_TOPRGU_SW_RST_NUM,
+ .has_swsysrst_en = true,
+};
+
static const struct mtk_wdt_data mt8183_data = {
.toprgu_sw_rst_num = MT8183_TOPRGU_SW_RST_NUM,
};
@@ -109,6 +120,28 @@ static const struct mtk_wdt_data mt8195_data = {
.toprgu_sw_rst_num = MT8195_TOPRGU_SW_RST_NUM,
};
+/**
+ * toprgu_reset_sw_en_unlocked() - enable/disable software control for reset bit
+ * @data: Pointer to instance of driver data.
+ * @id: Bit number identifying the reset to be enabled or disabled.
+ * @enable: If true, enable software control for that bit, disable otherwise.
+ *
+ * Context: The caller must hold lock of struct mtk_wdt_dev.
+ */
+static void toprgu_reset_sw_en_unlocked(struct mtk_wdt_dev *data,
+ unsigned long id, bool enable)
+{
+ u32 tmp;
+
+ tmp = readl(data->wdt_base + WDT_SWSYSRST_EN);
+ if (enable)
+ tmp |= BIT(id);
+ else
+ tmp &= ~BIT(id);
+
+ writel(tmp, data->wdt_base + WDT_SWSYSRST_EN);
+}
+
static int toprgu_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
@@ -119,6 +152,9 @@ static int toprgu_reset_update(struct reset_controller_dev *rcdev,
spin_lock_irqsave(&data->lock, flags);
+ if (assert && data->has_swsysrst_en)
+ toprgu_reset_sw_en_unlocked(data, id, true);
+
tmp = readl(data->wdt_base + WDT_SWSYSRST);
if (assert)
tmp |= BIT(id);
@@ -127,6 +163,9 @@ static int toprgu_reset_update(struct reset_controller_dev *rcdev,
tmp |= WDT_SWSYS_RST_KEY;
writel(tmp, data->wdt_base + WDT_SWSYSRST);
+ if (!assert && data->has_swsysrst_en)
+ toprgu_reset_sw_en_unlocked(data, id, false);
+
spin_unlock_irqrestore(&data->lock, flags);
return 0;
@@ -406,6 +445,8 @@ static int mtk_wdt_probe(struct platform_device *pdev)
wdt_data->toprgu_sw_rst_num);
if (err)
return err;
+
+ mtk_wdt->has_swsysrst_en = wdt_data->has_swsysrst_en;
}
mtk_wdt->disable_wdt_extrst =
@@ -444,6 +485,7 @@ static const struct of_device_id mtk_wdt_dt_ids[] = {
{ .compatible = "mediatek,mt6589-wdt" },
{ .compatible = "mediatek,mt6795-wdt", .data = &mt6795_data },
{ .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data },
+ { .compatible = "mediatek,mt7988-wdt", .data = &mt7988_data },
{ .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },
{ .compatible = "mediatek,mt8186-wdt", .data = &mt8186_data },
{ .compatible = "mediatek,mt8188-wdt", .data = &mt8188_data },
diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
index 8e1be7ba0103..9215793a1c81 100644
--- a/drivers/watchdog/rti_wdt.c
+++ b/drivers/watchdog/rti_wdt.c
@@ -77,6 +77,11 @@ static int rti_wdt_start(struct watchdog_device *wdd)
{
u32 timer_margin;
struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(wdd->parent);
+ if (ret)
+ return ret;
/* set timeout period */
timer_margin = (u64)wdd->timeout * wdt->freq;
@@ -343,6 +348,9 @@ static int rti_wdt_probe(struct platform_device *pdev)
if (last_ping)
watchdog_set_last_hw_keepalive(wdd, last_ping);
+ if (!watchdog_hw_running(wdd))
+ pm_runtime_put_sync(&pdev->dev);
+
return 0;
err_iomap:
@@ -357,7 +365,10 @@ static void rti_wdt_remove(struct platform_device *pdev)
struct rti_wdt_device *wdt = platform_get_drvdata(pdev);
watchdog_unregister_device(&wdt->wdd);
- pm_runtime_put(&pdev->dev);
+
+ if (!pm_runtime_suspended(&pdev->dev))
+ pm_runtime_put(&pdev->dev);
+
pm_runtime_disable(&pdev->dev);
}
diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c
index 5f501b41faf9..e28ead24c520 100644
--- a/drivers/watchdog/starfive-wdt.c
+++ b/drivers/watchdog/starfive-wdt.c
@@ -202,12 +202,14 @@ static u32 starfive_wdt_ticks_to_sec(struct starfive_wdt *wdt, u32 ticks)
/* Write unlock-key to unlock. Write other value to lock. */
static void starfive_wdt_unlock(struct starfive_wdt *wdt)
+ __acquires(&wdt->lock)
{
spin_lock(&wdt->lock);
writel(wdt->variant->unlock_key, wdt->base + wdt->variant->unlock);
}
static void starfive_wdt_lock(struct starfive_wdt *wdt)
+ __releases(&wdt->lock)
{
writel(~wdt->variant->unlock_key, wdt->base + wdt->variant->unlock);
spin_unlock(&wdt->lock);
@@ -504,7 +506,7 @@ err_exit:
return ret;
}
-static int starfive_wdt_remove(struct platform_device *pdev)
+static void starfive_wdt_remove(struct platform_device *pdev)
{
struct starfive_wdt *wdt = platform_get_drvdata(pdev);
@@ -516,8 +518,6 @@ static int starfive_wdt_remove(struct platform_device *pdev)
else
/* disable clock without PM */
starfive_wdt_disable_clock(wdt);
-
- return 0;
}
static void starfive_wdt_shutdown(struct platform_device *pdev)
@@ -587,7 +587,7 @@ MODULE_DEVICE_TABLE(of, starfive_wdt_match);
static struct platform_driver starfive_wdt_driver = {
.probe = starfive_wdt_probe,
- .remove = starfive_wdt_remove,
+ .remove_new = starfive_wdt_remove,
.shutdown = starfive_wdt_shutdown,
.driver = {
.name = "starfive-wdt",
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c
index 89a54b6645bd..8d5f67acbff2 100644
--- a/drivers/watchdog/txx9wdt.c
+++ b/drivers/watchdog/txx9wdt.c
@@ -98,7 +98,7 @@ static struct watchdog_device txx9wdt = {
.ops = &txx9wdt_ops,
};
-static int __init txx9wdt_probe(struct platform_device *dev)
+static int txx9wdt_probe(struct platform_device *dev)
{
int ret;
@@ -145,12 +145,11 @@ exit:
return ret;
}
-static int __exit txx9wdt_remove(struct platform_device *dev)
+static void txx9wdt_remove(struct platform_device *dev)
{
watchdog_unregister_device(&txx9wdt);
clk_disable_unprepare(txx9_imclk);
clk_put(txx9_imclk);
- return 0;
}
static void txx9wdt_shutdown(struct platform_device *dev)
@@ -159,14 +158,14 @@ static void txx9wdt_shutdown(struct platform_device *dev)
}
static struct platform_driver txx9wdt_driver = {
- .remove = __exit_p(txx9wdt_remove),
+ .probe = txx9wdt_probe,
+ .remove_new = txx9wdt_remove,
.shutdown = txx9wdt_shutdown,
.driver = {
.name = "txx9wdt",
},
};
-
-module_platform_driver_probe(txx9wdt_driver, txx9wdt_probe);
+module_platform_driver(txx9wdt_driver);
MODULE_DESCRIPTION("TXx9 Watchdog Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 15df74e11a59..e2bd266b1b5b 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -1073,6 +1073,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
/* Fill in the data structures */
cdev_init(&wd_data->cdev, &watchdog_fops);
+ wd_data->cdev.owner = wdd->ops->owner;
/* Add the device */
err = cdev_device_add(&wd_data->cdev, &wd_data->dev);
@@ -1087,8 +1088,6 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
return err;
}
- wd_data->cdev.owner = wdd->ops->owner;
-
/* Record time of most recent heartbeat as 'just before now'. */
wd_data->last_hw_keepalive = ktime_sub(ktime_get(), 1);
watchdog_set_open_deadline(wd_data);