From: "Janusz Użycki" <j.uzycki@elproma.com.pl>
To: Guenter Roeck <linux@roeck-us.net>, linux-watchdog@vger.kernel.org
Cc: Wim Van Sebroeck <wim@iguana.be>
Subject: Re: watchdog: watchdog_dev: WATCHDOG_KEEP_ON feature
Date: Mon, 08 Sep 2014 03:18:28 +0200 [thread overview]
Message-ID: <540D03E4.9090704@elproma.com.pl> (raw)
In-Reply-To: <540D02E1.90403@elproma.com.pl>
[-- Attachment #1: Type: text/plain, Size: 10040 bytes --]
I diffed to bad git's HEAD, sorry. I resend the patch.
Janusz
W dniu 2014-09-08 03:14, Janusz Użycki pisze:
> W dniu 2014-09-07 19:18, Guenter Roeck pisze:
>> On 09/04/2014 08:47 AM, Janusz Użycki wrote:
>>> Some applications require to start watchdog before userspace
>>> software. This patch enables such feature. Only WATCHDOG_KERNEL_PING
>>> flag is necessary to enable it (attached example for
>>> stmp3xxx_rtc_wdt.c). Moreover kernel's ping is re-enabled when
>>> userspace software closed watchdog using the magic character. The
>>> features improves kernel's reliable if hardware watchdog is available.
>>> * Can you comment the proposed patch?
>>> * Shoud dynamic or static timer_list be used (small structure...)?
> dynamic or static timer?
>
>>> * I also added wdd->ops->ref/unref calls but I'm afraid that even
>>> original code is buggy in watchdog_dev.c. Is any driver that uses
>>> the pointers? In my opinion watchdog_open() should call
>>> wdd->ops->ref() before watchdog_start() and watchdog_release()
>>> should call wdd->ops->unref() before module_put(). Otherwise fault
>>> is possible if watchdog module is unloaded.
>>> * I noticed that current watchdog core does not support
>>> suspend/resume case. If you want to use suspend without the patch
>>> you need to close a watchdog in userspace using the magic character
>>> before suspend command. With the patch you must to use
>>> WDIOC_SETOPTIONS ioctl and WDIOS_DISABLECARD/WDIOS_ENABLECARD. Is
>>> there any other method to suspend with watchdog?
> Can kernel suspend a started (stoppable) watchdog? It dissapeared in
> 3.x. Now userland reaction seems to be required.
>
>> I like the basic idea. Couple of comments.
> Thanks. Below a fixed patch code.
>
>> Please read and follow Documentation/SubmittingPatches.
>> Long lines as above are discouraged, as is sending patches
>> as attachment. As you can see, the patch disappears in the
>> reply, making it very hard to comment on it.
> fixed.
> I also attached the patch file - I don't trust email client in text
> formatting (tabs)
>
>> I would suggest to just modify the timer to half the timeout value,
>> and then just ping the watchdog unconditionally whenever the callback
>> runs. The timer should stop when the watchdog is opened, so there
>> should not be a need to check its open status in the callback.
> you are right, fixed
>
>> I don't think there is a need to manipulate the driver reference
>> count when the kernel timer starts and stops. You already run
>> module_get and module_put during registration / unregistration.
> removed
>
>> I would not call this "kernel ping". We'll need to find a better
>> name. Proposals welcome. Something indicating the status, ie something
>> indicating that the wdt is always running and can not be stopped.
> "keep on" proposed (I changed the subject also)
>
>> You would not update the status in the affected driver(s) by
>> setting the flag in the probe function. You can use the status
>> flag initialization for that purpose.
> fixed as example
>
>> Also, we'll need to know if
>> the driver you changed is always affected or only in your system.
>> Either case, driver patches need to be submitted separately.
> I used to add similar code to different wachdog drivers for embedded
> boards. This time I work under quite new kernel 3.14 and therefore I
> finally decided to submit a patch.
> The feature should be generally used for all hardware watchdogs.
> Unfortunately some drivers uses own timers, eg. to increase timeout
> period. Another exception is softdog.
>
>> We'll need to tie this functionality with parallel efforts
>> to add similar code into individual drivers. There is one patch
>> along that line pending right now [1],
> I saw it and agree - they can cooperate
>
>> and I think there is similar
>> support in other drivers. dw_wdt is one example where the wdt can
>> not be stopped after it was started, of_xilinx_wdt is another.
> So it is similar to at91sam9g20 as I remember but Atmel's watchdog
> driver uses constant hardware timeout stretched by the driver.
>
>> Given that, there are two use states to consider: WDT is always running,
>> and WDT can not be stopped after it was started once. We should cover
>> both cases.
> and third: ability to stop watchdog (if possible) for suspend
>
>> The feature should have DT support from the beginning if possible,
>> though it should be added as a separate patch in case there is
>> a hiccup with the DT folks.
> Can you give more details?
>
>> It might be worthwhile exploring if the same mechanism can be used
>> to augment user space pinging with kernel ping if the maximum timeout
>> is too short to be handled by user space alone. That should be a
>> separate patch, but we need to keep this use case in mind.
> I agree - unification is welcomed.
>
> Janusz
>>
>> Guenter
>>
>> ---
>> [1] http://patchwork.roeck-us.net/patch/1890/
>
Signed-off-by: Janusz Uzycki <j.uzycki@elproma.com.pl>
diff --git a/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c
b/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c
index b4d6b34..3546f03 100644
--- a/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c
+++ b/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c
@@ -67,7 +67,7 @@ static struct watchdog_device stmp3xxx_wdd = {
.ops = &stmp3xxx_wdt_ops,
.min_timeout = 1,
.max_timeout = STMP3XXX_MAX_TIMEOUT,
- .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
+ .status = WATCHDOG_NOWAYOUT_INIT_STATUS | WATCHDOG_KEEP_ON,
};
static int stmp3xxx_wdt_probe(struct platform_device *pdev)
diff --git a/linux-3.14.17/drivers/watchdog/watchdog_dev.c
b/linux-3.14.17/drivers/watchdog/watchdog_dev.c
index 6aaefba..f16955d 100644
--- a/linux-3.14.17/drivers/watchdog/watchdog_dev.c
+++ b/linux-3.14.17/drivers/watchdog/watchdog_dev.c
@@ -41,6 +41,8 @@
#include <linux/miscdevice.h> /* For handling misc devices */
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
+#include <linux/slab.h> /* for 'keep on' timer (dynamic) */
+#include <linux/jiffies.h> /* for 'keep on' timer */
#include "watchdog_core.h"
@@ -277,6 +279,29 @@ out_ioctl:
return err;
}
+/* 'keep on' feature */
+static void watchdog_keepon_timer_cb(unsigned long data)
+{
+ struct watchdog_device *wdd = (struct watchdog_device *)data;
+ watchdog_ping(wdd);
+ /* call next ping half the timeout value */
+ mod_timer(wdd->keepon_timer,
+ jiffies + wdd->timeout * (HZ/2));
+}
+
+static void watchdog_keepon_start(struct watchdog_device *wdd)
+{
+ watchdog_start(wdd);
+ /* watchdog_keepon_timer_cb((unsigned long)wdd); or the code below: */
+ watchdog_ping(wdd);
+ mod_timer(wdd->keepon_timer, jiffies + HZ/2);
+}
+
+static void watchdog_keepon_stop(struct watchdog_device *wdd)
+{
+ del_timer_sync(wdd->keepon_timer);
+}
+
/*
* watchdog_write: writes to the watchdog.
* @file: file from VFS
@@ -430,6 +455,9 @@ static int watchdog_open(struct inode *inode, struct
file *file)
if (!try_module_get(wdd->ops->owner))
goto out;
+ if (test_bit(WDOG_KEEP_ON, &wdd->status))
+ watchdog_keepon_stop(wdd);
+
err = watchdog_start(wdd);
if (err < 0)
goto out_mod;
@@ -472,8 +500,13 @@ static int watchdog_release(struct inode *inode,
struct file *file)
if (!test_bit(WDOG_ACTIVE, &wdd->status))
err = 0;
else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
- !(wdd->info->options & WDIOF_MAGICCLOSE))
- err = watchdog_stop(wdd);
+ !(wdd->info->options & WDIOF_MAGICCLOSE)) {
+ if (test_bit(WDOG_KEEP_ON, &wdd->status)) {
+ watchdog_keepon_start(wdd);
+ err = 0;
+ } else
+ err = watchdog_stop(wdd);
+ }
/* If the watchdog was not stopped, send a keepalive ping */
if (err < 0) {
@@ -524,6 +557,18 @@ int watchdog_dev_register(struct watchdog_device
*watchdog)
{
int err, devno;
+ if (test_bit(WDOG_KEEP_ON, &watchdog->status)) {
+ if (!try_module_get(watchdog->ops->owner))
+ return -ENODEV;
+ watchdog->keepon_timer =
+ kzalloc(sizeof(*watchdog->keepon_timer), GFP_KERNEL);
+ if (!watchdog->keepon_timer)
+ return -ENOMEM;
+ setup_timer(watchdog->keepon_timer, watchdog_keepon_timer_cb,
+ (unsigned long)watchdog);
+ watchdog_keepon_start(watchdog);
+ }
+
if (watchdog->id == 0) {
old_wdd = watchdog;
watchdog_miscdev.parent = watchdog->parent;
@@ -575,6 +620,15 @@ int watchdog_dev_unregister(struct watchdog_device
*watchdog)
misc_deregister(&watchdog_miscdev);
old_wdd = NULL;
}
+
+ if (test_bit(WDOG_KEEP_ON, &watchdog->status) ||
+ watchdog->keepon_timer) {
+ watchdog_keepon_stop(watchdog);
+ kfree(watchdog->keepon_timer);
+ watchdog->keepon_timer = NULL;
+ watchdog_stop(watchdog);
+ module_put(watchdog->ops->owner);
+ }
return 0;
}
diff --git a/linux-3.14.17/include/linux/watchdog.h
b/linux-3.14.17/include/linux/watchdog.h
index 2a3038e..57b552a 100644
--- a/linux-3.14.17/include/linux/watchdog.h
+++ b/linux-3.14.17/include/linux/watchdog.h
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/cdev.h>
+#include <linux/timer.h> /* for 'keep on' timer */
#include <uapi/linux/watchdog.h>
struct watchdog_ops;
@@ -95,6 +96,9 @@ struct watchdog_device {
#define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */
#define WDOG_NO_WAY_OUT 3 /* Is 'nowayout' feature set ? */
#define WDOG_UNREGISTERED 4 /* Has the device been unregistered */
+#define WDOG_KEEP_ON 5 /* Is 'keep on' feature set? */
+ struct timer_list *keepon_timer;/* 'keep on' timer */
+#define WATCHDOG_KEEP_ON (1 << WDOG_KEEP_ON)
};
#ifdef CONFIG_WATCHDOG_NOWAYOUT
[-- Attachment #2: watchdog_dev.patch --]
[-- Type: text/plain, Size: 4688 bytes --]
Signed-off-by: Janusz Uzycki <j.uzycki@elproma.com.pl>
diff --git a/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c b/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c
index b4d6b34..3546f03 100644
--- a/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c
+++ b/linux-3.14.17/drivers/watchdog/stmp3xxx_rtc_wdt.c
@@ -67,7 +67,7 @@ static struct watchdog_device stmp3xxx_wdd = {
.ops = &stmp3xxx_wdt_ops,
.min_timeout = 1,
.max_timeout = STMP3XXX_MAX_TIMEOUT,
- .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
+ .status = WATCHDOG_NOWAYOUT_INIT_STATUS | WATCHDOG_KEEP_ON,
};
static int stmp3xxx_wdt_probe(struct platform_device *pdev)
diff --git a/linux-3.14.17/drivers/watchdog/watchdog_dev.c b/linux-3.14.17/drivers/watchdog/watchdog_dev.c
index 6aaefba..f16955d 100644
--- a/linux-3.14.17/drivers/watchdog/watchdog_dev.c
+++ b/linux-3.14.17/drivers/watchdog/watchdog_dev.c
@@ -41,6 +41,8 @@
#include <linux/miscdevice.h> /* For handling misc devices */
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
+#include <linux/slab.h> /* for 'keep on' timer (dynamic) */
+#include <linux/jiffies.h> /* for 'keep on' timer */
#include "watchdog_core.h"
@@ -277,6 +279,29 @@ out_ioctl:
return err;
}
+/* 'keep on' feature */
+static void watchdog_keepon_timer_cb(unsigned long data)
+{
+ struct watchdog_device *wdd = (struct watchdog_device *)data;
+ watchdog_ping(wdd);
+ /* call next ping half the timeout value */
+ mod_timer(wdd->keepon_timer,
+ jiffies + wdd->timeout * (HZ/2));
+}
+
+static void watchdog_keepon_start(struct watchdog_device *wdd)
+{
+ watchdog_start(wdd);
+ /* watchdog_keepon_timer_cb((unsigned long)wdd); or the code below: */
+ watchdog_ping(wdd);
+ mod_timer(wdd->keepon_timer, jiffies + HZ/2);
+}
+
+static void watchdog_keepon_stop(struct watchdog_device *wdd)
+{
+ del_timer_sync(wdd->keepon_timer);
+}
+
/*
* watchdog_write: writes to the watchdog.
* @file: file from VFS
@@ -430,6 +455,9 @@ static int watchdog_open(struct inode *inode, struct file *file)
if (!try_module_get(wdd->ops->owner))
goto out;
+ if (test_bit(WDOG_KEEP_ON, &wdd->status))
+ watchdog_keepon_stop(wdd);
+
err = watchdog_start(wdd);
if (err < 0)
goto out_mod;
@@ -472,8 +500,13 @@ static int watchdog_release(struct inode *inode, struct file *file)
if (!test_bit(WDOG_ACTIVE, &wdd->status))
err = 0;
else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
- !(wdd->info->options & WDIOF_MAGICCLOSE))
- err = watchdog_stop(wdd);
+ !(wdd->info->options & WDIOF_MAGICCLOSE)) {
+ if (test_bit(WDOG_KEEP_ON, &wdd->status)) {
+ watchdog_keepon_start(wdd);
+ err = 0;
+ } else
+ err = watchdog_stop(wdd);
+ }
/* If the watchdog was not stopped, send a keepalive ping */
if (err < 0) {
@@ -524,6 +557,18 @@ int watchdog_dev_register(struct watchdog_device *watchdog)
{
int err, devno;
+ if (test_bit(WDOG_KEEP_ON, &watchdog->status)) {
+ if (!try_module_get(watchdog->ops->owner))
+ return -ENODEV;
+ watchdog->keepon_timer =
+ kzalloc(sizeof(*watchdog->keepon_timer), GFP_KERNEL);
+ if (!watchdog->keepon_timer)
+ return -ENOMEM;
+ setup_timer(watchdog->keepon_timer, watchdog_keepon_timer_cb,
+ (unsigned long)watchdog);
+ watchdog_keepon_start(watchdog);
+ }
+
if (watchdog->id == 0) {
old_wdd = watchdog;
watchdog_miscdev.parent = watchdog->parent;
@@ -575,6 +620,15 @@ int watchdog_dev_unregister(struct watchdog_device *watchdog)
misc_deregister(&watchdog_miscdev);
old_wdd = NULL;
}
+
+ if (test_bit(WDOG_KEEP_ON, &watchdog->status) ||
+ watchdog->keepon_timer) {
+ watchdog_keepon_stop(watchdog);
+ kfree(watchdog->keepon_timer);
+ watchdog->keepon_timer = NULL;
+ watchdog_stop(watchdog);
+ module_put(watchdog->ops->owner);
+ }
return 0;
}
diff --git a/linux-3.14.17/include/linux/watchdog.h b/linux-3.14.17/include/linux/watchdog.h
index 2a3038e..57b552a 100644
--- a/linux-3.14.17/include/linux/watchdog.h
+++ b/linux-3.14.17/include/linux/watchdog.h
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/cdev.h>
+#include <linux/timer.h> /* for 'keep on' timer */
#include <uapi/linux/watchdog.h>
struct watchdog_ops;
@@ -95,6 +96,9 @@ struct watchdog_device {
#define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */
#define WDOG_NO_WAY_OUT 3 /* Is 'nowayout' feature set ? */
#define WDOG_UNREGISTERED 4 /* Has the device been unregistered */
+#define WDOG_KEEP_ON 5 /* Is 'keep on' feature set? */
+ struct timer_list *keepon_timer;/* 'keep on' timer */
+#define WATCHDOG_KEEP_ON (1 << WDOG_KEEP_ON)
};
#ifdef CONFIG_WATCHDOG_NOWAYOUT
next prev parent reply other threads:[~2014-09-08 1:18 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <S1751381AbaIDOwq/20140904145246Z+988@vger.kernel.org>
2014-09-04 15:47 ` watchdog: WatchDog Timer Driver Core: ping a hardware watchdog in kernel's space Janusz Użycki
2014-09-07 17:18 ` Guenter Roeck
2014-09-08 1:14 ` watchdog: watchdog_dev: WATCHDOG_KEEP_ON feature Janusz Użycki
2014-09-08 1:18 ` Janusz Użycki [this message]
2014-09-08 3:24 ` Guenter Roeck
2014-09-08 3:16 ` Guenter Roeck
2014-09-08 12:14 ` Janusz Użycki
2014-09-10 17:24 ` Janusz Użycki
2014-09-11 10:47 ` Janusz Użycki
2014-09-17 11:09 ` Janusz Użycki
2014-09-18 11:07 ` watchdog's pm support preffered implementation Janusz Użycki
2014-09-18 21:40 ` Janusz Użycki
2014-09-18 22:02 ` Janusz Użycki
2014-09-19 3:11 ` Guenter Roeck
2014-09-19 9:46 ` Janusz Użycki
2014-09-19 11:23 ` timers vs drivers suspend race Janusz Użycki
2014-09-19 13:44 ` Janusz Użycki
2014-09-19 16:21 ` watchdog's pm support preffered implementation Guenter Roeck
2014-09-23 12:07 ` Janusz Użycki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=540D03E4.9090704@elproma.com.pl \
--to=j.uzycki@elproma.com.pl \
--cc=linux-watchdog@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=wim@iguana.be \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox