From 38d75297745f04206db9c29bdd75557f0344c7cc Mon Sep 17 00:00:00 2001 From: Curtis Klein Date: Tue, 5 Dec 2023 11:05:22 -0800 Subject: watchdog: set cdev owner before adding When the new watchdog character device is registered, it becomes available for opening. This creates a race where userspace may open the device before the character device's owner is set. This results in an imbalance in module_get calls as the cdev_get in cdev_open will not increment the reference count on the watchdog driver module. This causes problems when the watchdog character device is released as the module loader's reference will also be released. This makes it impossible to open the watchdog device later on as it now appears that the module is being unloaded. The open will fail with -ENXIO from chrdev_open. The legacy watchdog device will fail with -EBUSY from the try_module_get in watchdog_open because it's module owner is the watchdog core module so it can still be opened but it will fail to get a refcount on the underlying watchdog device driver. Fixes: 72139dfa2464 ("watchdog: Fix the race between the release of watchdog_core_data and cdev") Signed-off-by: Curtis Klein Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231205190522.55153-1-curtis.klein@hpe.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/watchdog_dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/watchdog') 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); -- cgit v1.2.3 From 86aa2919f1ae4ee7f90260d028f7572263d1c715 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 6 Nov 2023 16:48:09 +0100 Subject: watchdog: at91sam9: Stop using module_platform_driver_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On today's platforms the benefit of platform_driver_probe() isn't that relevant any more. It allows to drop some code after booting (or module loading) for .probe() and discard the .remove() function completely if the driver is built-in. This typically saves a few 100k. The downside of platform_driver_probe() is that the driver cannot be bound and unbound at runtime which is ancient and also slightly complicates testing. There are also thoughts to deprecate platform_driver_probe() because it adds some complexity in the driver core for little gain. Also many drivers don't use it correctly. This driver for example misses to mark the driver struct with __refdata which is needed to suppress a (W=1) modpost warning: WARNING: modpost: drivers/watchdog/at91sam9_wdt: section mismatch in reference: at91wdt_driver+0x4 (section: .data) -> at91wdt_remove (section: .exit.text) Signed-off-by: Uwe Kleine-König Acked-by: Nicolas Ferre Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231106154807.3866712-2-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/at91sam9_wdt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index b111b28acb94..507adb12754d 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,7 +372,7 @@ static int __init at91wdt_probe(struct platform_device *pdev) return 0; } -static int __exit at91wdt_remove(struct platform_device *pdev) +static int at91wdt_remove(struct platform_device *pdev) { struct at91wdt *wdt = platform_get_drvdata(pdev); watchdog_unregister_device(&wdt->wdd); @@ -393,14 +393,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 = 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 "); MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors"); -- cgit v1.2.3 From de81f74b11e9ffdf5362961c2efea13bef11aefd Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 6 Nov 2023 16:48:10 +0100 Subject: watchdog: txx9: Stop using module_platform_driver_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On today's platforms the benefit of platform_driver_probe() isn't that relevant any more. It allows to drop some code after booting (or module loading) for .probe() and discard the .remove() function completely if the driver is built-in. This typically saves a few 100k. The downside of platform_driver_probe() is that the driver cannot be bound and unbound at runtime which is ancient and also slightly complicates testing. There are also thoughts to deprecate platform_driver_probe() because it adds some complexity in the driver core for little gain. Also many drivers don't use it correctly. This driver for example misses to mark the driver struct with __refdata which is needed to suppress a (W=1) modpost warning: WARNING: modpost: drivers/watchdog/txx9wdt: section mismatch in reference: txx9wdt_driver+0x4 (section: .data) -> txx9wdt_remove (section: .exit.text) Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231106154807.3866712-3-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/txx9wdt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index 89a54b6645bd..f900c519ed63 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,7 +145,7 @@ exit: return ret; } -static int __exit txx9wdt_remove(struct platform_device *dev) +static int txx9wdt_remove(struct platform_device *dev) { watchdog_unregister_device(&txx9wdt); clk_disable_unprepare(txx9_imclk); @@ -159,14 +159,14 @@ static void txx9wdt_shutdown(struct platform_device *dev) } static struct platform_driver txx9wdt_driver = { - .remove = __exit_p(txx9wdt_remove), + .probe = txx9wdt_probe, + .remove = 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"); -- cgit v1.2.3 From 6a7b3de6a35a8bcdf28f33d70d2b30655da29a4d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 6 Nov 2023 16:48:11 +0100 Subject: watchdog: at91sam9_wdt: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Acked-by: Nicolas Ferre Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231106154807.3866712-4-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/at91sam9_wdt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index 507adb12754d..2c6474cb858b 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -372,15 +372,13 @@ static int at91wdt_probe(struct platform_device *pdev) return 0; } -static int 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) @@ -394,7 +392,7 @@ MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids); static struct platform_driver at91wdt_driver = { .probe = at91wdt_probe, - .remove = at91wdt_remove, + .remove_new = at91wdt_remove, .driver = { .name = "at91_wdt", .of_match_table = of_match_ptr(at91_wdt_dt_ids), -- cgit v1.2.3 From 2faef2754409a8d26ea7cec1ca369fabb97b5327 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 6 Nov 2023 16:48:12 +0100 Subject: watchdog: starfive-wdt: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231106154807.3866712-5-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/starfive-wdt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c index 5f501b41faf9..16df92837c5d 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -504,7 +504,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 +516,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 +585,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", -- cgit v1.2.3 From da24118732925d5fd5b9ce8aff58b213a2e051ed Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 6 Nov 2023 16:48:13 +0100 Subject: watchdog: txx9wdt: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new(), which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231106154807.3866712-6-u.kleine-koenig@pengutronix.de Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/txx9wdt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index f900c519ed63..8d5f67acbff2 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c @@ -145,12 +145,11 @@ exit: return ret; } -static int 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) @@ -160,7 +159,7 @@ static void txx9wdt_shutdown(struct platform_device *dev) static struct platform_driver txx9wdt_driver = { .probe = txx9wdt_probe, - .remove = txx9wdt_remove, + .remove_new = txx9wdt_remove, .shutdown = txx9wdt_shutdown, .driver = { .name = "txx9wdt", -- cgit v1.2.3 From dced0b3e51dd2af3730efe14dd86b5e3173f0a65 Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Wed, 13 Dec 2023 14:53:38 -0700 Subject: watchdog/hpwdt: Only claim UNKNOWN NMI if from iLO Avoid unnecessary crashes by claiming only NMIs that are due to ERROR signalling or generated by the hpwdt hardware device. The code does this, but only for iLO5. The intent was to preserve legacy, Gen9 and earlier, semantics of using hpwdt for error containtment as hardware/firmware would signal fatal IO errors as an NMI with the expectation of hpwdt crashing the system. Howerver, these IO errors should be received by hpwdt as an NMI_IO_CHECK. So the test is overly permissive and should not be limited to only ilo5. We need to enable this protection for future iLOs not matching the current PCI IDs. Fixes: 62290a5c194b ("watchdog: hpwdt: Claim NMIs generated by iLO5") Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213215340.495734-2-jerry.hoemann@hpe.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index f79f932bca14..79ed1626d8ea 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -178,7 +178,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) + if (ulReason == NMI_UNKNOWN && !mynmi) return NMI_DONE; if (ilo5 && !pretimeout && !mynmi) -- cgit v1.2.3 From 2b276d52d83d1e48af53646b4c03c171b2d7d4f4 Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Wed, 13 Dec 2023 14:53:39 -0700 Subject: watchdog/hpwdt: Remove redundant test. ProLiants of vintage to have an iLO 5, no longer send watchdog NMI as an IO CHECK. They are presented to hpwdt_pretimeout as NMI_UNKNOWN. The preceding if statement rejects if !mynmi irrespective of value of pretimeout making this if statement redundant. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213215340.495734-3-jerry.hoemann@hpe.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 79ed1626d8ea..d5c0aa3ef069 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -181,9 +181,6 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) if (ulReason == NMI_UNKNOWN && !mynmi) return NMI_DONE; - if (ilo5 && !pretimeout && !mynmi) - return NMI_DONE; - if (kdumptimeout < 0) hpwdt_stop(); else if (kdumptimeout == 0) -- cgit v1.2.3 From 91c437ea47045379db870fd0454d8778573b41e0 Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Wed, 13 Dec 2023 14:53:40 -0700 Subject: watchdog/hpwdt: Remove unused variable Remove the unused variable ilo5. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213215340.495734-4-jerry.hoemann@hpe.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index d5c0aa3ef069..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); @@ -360,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: -- cgit v1.2.3 From f33f5b1fd1be5f5106d16f831309648cb0f1c31d Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 12 Nov 2023 18:32:51 +0100 Subject: watchdog: bcm2835_wdt: Fix WDIOC_SETTIMEOUT handling Users report about the unexpected behavior for setting timeouts above 15 sec on Raspberry Pi. According to watchdog-api.rst the ioctl WDIOC_SETTIMEOUT shouldn't fail because of hardware limitations. But looking at the code shows that max_timeout based on the register value PM_WDOG_TIME_SET, which is the maximum. Since 664a39236e71 ("watchdog: Introduce hardware maximum heartbeat in watchdog core") the watchdog core is able to handle this problem. This fix has been tested with watchdog-test from selftests. Link: https://bugzilla.kernel.org/show_bug.cgi?id=217374 Fixes: 664a39236e71 ("watchdog: Introduce hardware maximum heartbeat in watchdog core") Signed-off-by: Stefan Wahren Reviewed-by: Florian Fainelli Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231112173251.4827-1-wahrenst@gmx.net Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/bcm2835_wdt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/watchdog') 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), }; -- cgit v1.2.3 From 137c9e08e5e542d58aa606b0bb4f0990117309a0 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 20 Nov 2023 18:22:31 +0000 Subject: watchdog: mediatek: mt7988: add wdt support Add support for watchdog and reset generator unit of the MediaTek MT7988 SoC. Signed-off-by: Daniel Golle Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/c0cf5f701801cce60470853fa15f1d9dced78c4f.1700504385.git.daniel@makrotopia.org Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mtk_wdt.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/watchdog') 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 }, -- cgit v1.2.3 From f77999887235f8c378af343df11a6bcedda5b284 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 22 Nov 2023 08:51:18 +0000 Subject: watchdog: starfive: add lock annotations to fix context imbalances Add the necessary __acquires() and __releases() to the functions that take and release the wdt lock to avoid the following sparse warnings: drivers/watchdog/starfive-wdt.c:204:13: warning: context imbalance in 'starfive_wdt_unlock' - wrong count at exit drivers/watchdog/starfive-wdt.c:212:9: warning: context imbalance in 'starfive_wdt_lock' - unexpected unlock Signed-off-by: Ben Dooks Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231122085118.177589-1-ben.dooks@codethink.co.uk Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/starfive-wdt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c index 16df92837c5d..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); -- cgit v1.2.3 From c1a6edf3b541e44e78f10bc6024df779715723f1 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Wed, 13 Dec 2023 19:31:10 +0530 Subject: watchdog: rti_wdt: Drop runtime pm reference count when watchdog is unused Call runtime_pm_put*() if watchdog is not already started during probe and re enable it in watchdog start as required. On K3 SoCs, watchdogs and their corresponding CPUs are under same power-domain, so if the reference count of unused watchdogs aren't dropped, it will lead to CPU hotplug failures as Device Management firmware won't allow to turn off the power-domain due to dangling reference count. Fixes: 2d63908bdbfb ("watchdog: Add K3 RTI watchdog support") Signed-off-by: Vignesh Raghavendra Tested-by: Manorit Chawdhry Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213140110.938129-1-vigneshr@ti.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/rti_wdt.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/watchdog') 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); } -- cgit v1.2.3 From fed7d05382abca82883a8213d42601235073869b Mon Sep 17 00:00:00 2001 From: Werner Fischer Date: Wed, 13 Dec 2023 10:45:22 +0100 Subject: watchdog: it87_wdt: add blank line after variable declaration This patch fixes the following checkpatch.pl warning: WARNING: Missing a blank line after declarations Signed-off-by: Werner Fischer Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213094525.11849-1-devlists@wefi.net Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/it87_wdt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index e888b1bdd1f2..6b7f7ec03633 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -146,6 +146,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); -- cgit v1.2.3 From 133530a5b99d6755bb9f712405d5d1a493cbaeab Mon Sep 17 00:00:00 2001 From: Werner Fischer Date: Wed, 13 Dec 2023 10:45:23 +0100 Subject: watchdog: it87_wdt: Remove redundant max_units setting Commit 893dc8b5c978 ("watchdog: it87: Drop support for resetting watchdog though CIR and Game port") removed the try_gameport variable, and left max_units setting redundant. To clean up the code, this patch removes this redundant setting. Signed-off-by: Werner Fischer Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213094525.11849-2-devlists@wefi.net Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/it87_wdt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index 6b7f7ec03633..ca377096bdd7 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -274,10 +274,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: @@ -287,9 +283,11 @@ static int __init it87_wdt_init(void) case IT8655_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: -- cgit v1.2.3 From ab6dea00fd6d148deecf2e8baaf0c110b35d7cea Mon Sep 17 00:00:00 2001 From: Werner Fischer Date: Wed, 13 Dec 2023 10:45:24 +0100 Subject: watchdog: it87_wdt: Add IT8659 ID This patch adds watchdog support for the ITE IT8659 watchdog. IT8659 watchdog works in the same way as the other watchdogs supported by it87_wdt. Before this patch, IT8659 watchdog is not supported. After a modprobe, dmesg reports: it87_wdt: Unknown Chip found, Chip 8659 Revision 0007 With this patch, modprobe it87_wdt recognizes the watchdog as the dmesg output shows: it87_wdt: Chip IT8659 revision 7 initialized. timeout=60 sec (nowayout=0 testmode=0) Watchdog tests on a YANLING YL-ALP3L2C-1235U system have been successful, the watchdog works as expected with this patch. Signed-off-by: Werner Fischer Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213094525.11849-3-devlists@wefi.net Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/it87_wdt.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index ca377096bdd7..f6a344c002af 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 @@ -281,6 +282,7 @@ 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: -- cgit v1.2.3 From d12971849d71781c1e4ffd1117d4878ce233d319 Mon Sep 17 00:00:00 2001 From: Werner Fischer Date: Wed, 13 Dec 2023 10:45:25 +0100 Subject: watchdog: it87_wdt: Keep WDTCTRL bit 3 unmodified for IT8784/IT8786 WDTCTRL bit 3 sets the mode choice for the clock input of IT8784/IT8786. Some motherboards require this bit to be set to 1 (= PCICLK mode), otherwise the watchdog functionality gets broken. The BIOS of those motherboards sets WDTCTRL bit 3 already to 1. Instead of setting all bits of WDTCTRL to 0 by writing 0x00 to it, keep bit 3 of it unchanged for IT8784/IT8786 chips. In this way, bit 3 keeps the status as set by the BIOS of the motherboard. Watchdog tests have been successful with this patch with the following systems: IT8784: Thomas-Krenn LES plus v2 (YANLING YL-KBRL2 V2) IT8786: Thomas-Krenn LES plus v3 (YANLING YL-CLU L2) IT8786: Thomas-Krenn LES network 6L v2 (YANLING YL-CLU6L) Link: https://lore.kernel.org/all/140b264d-341f-465b-8715-dacfe84b3f71@roeck-us.net/ Signed-off-by: Werner Fischer Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231213094525.11849-4-devlists@wefi.net Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/it87_wdt.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index f6a344c002af..9297a5891912 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -258,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(); @@ -316,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) { -- cgit v1.2.3 From 9546b21ea672aa961d5a89ea754214afed013f02 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 17 Dec 2023 22:26:59 -0800 Subject: watchdog: mlx_wdt: fix all kernel-doc warnings Correct kernel-doc warnings as reported by kernel test robot: mlx_wdt.c:56: warning: Function parameter or member 'wdt_type' not described in 'mlxreg_wdt' mlx_wdt.c:56: warning: Excess struct member 'device' description in 'mlxreg_wdt' mlx_wdt.c:56: warning: Excess struct member 'timeout' description in 'mlxreg_wdt' mlx_wdt.c:56: warning: Excess struct member 'wd_type' description in 'mlxreg_wdt' Signed-off-by: Randy Dunlap Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202312171701.xNkzdgdi-lkp@intel.com/ Cc: Michael Shych Cc: Wim Van Sebroeck Cc: Guenter Roeck Cc: linux-watchdog@vger.kernel.org Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20231218062659.26916-1-rdunlap@infradead.org Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mlx_wdt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/watchdog') 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; -- cgit v1.2.3