From: Michael Buesch <mb@bu3sch.de>
To: Tony Lindgren <tony@atomide.com>
Cc: Felipe Balbi <balbi@ti.com>, linux-omap <linux-omap@vger.kernel.org>
Subject: [PATCH] cbus-retu-wdt: Make the watchdog driver fully preemptible
Date: Wed, 02 Mar 2011 17:11:47 +0100 [thread overview]
Message-ID: <1299082307.13604.12.camel@marge> (raw)
Make the WDT driver fully preemptible.
This is required in order to apply a locking fix to retu_write_reg.
It also improves power management by using round_relative_jiffies().
Signed-off-by: Michael Buesch <mb@bu3sch.de>
---
Tony, thanks for the report on this issue.
You may apply the locking fix on to of this.
Index: linux-2.6.38-rc6/drivers/cbus/retu-wdt.c
===================================================================
--- linux-2.6.38-rc6.orig/drivers/cbus/retu-wdt.c 2011-03-02 16:08:59.022211654 +0100
+++ linux-2.6.38-rc6/drivers/cbus/retu-wdt.c 2011-03-02 16:29:43.215284501 +0100
@@ -58,13 +58,11 @@ struct retu_wdt_dev {
struct device *dev;
int users;
struct miscdevice retu_wdt_miscdev;
- struct timer_list ping_timer;
+ struct delayed_work ping_work;
};
static struct retu_wdt_dev *retu_wdt;
-static void retu_wdt_set_ping_timer(unsigned long enable);
-
static int _retu_modify_counter(unsigned int new)
{
if (retu_wdt)
@@ -86,6 +84,31 @@ static int retu_modify_counter(unsigned
return 0;
}
+/*
+ * Since retu watchdog cannot be disabled in hardware, we must kick it
+ * with a timer until userspace watchdog software takes over. Do this
+ * unless /dev/watchdog is open or CONFIG_WATCHDOG_NOWAYOUT is set.
+ */
+static void retu_wdt_ping_enable(struct retu_wdt_dev *wdev)
+{
+ _retu_modify_counter(RETU_WDT_MAX_TIMER);
+ schedule_delayed_work(&wdev->ping_work,
+ round_jiffies_relative(RETU_WDT_DEFAULT_TIMER * HZ));
+}
+
+static void retu_wdt_ping_disable(struct retu_wdt_dev *wdev)
+{
+ _retu_modify_counter(RETU_WDT_MAX_TIMER);
+ cancel_delayed_work_sync(&wdev->ping_work);
+}
+
+static void retu_wdt_ping_work(struct work_struct *work)
+{
+ struct retu_wdt_dev *wdev = container_of(to_delayed_work(work),
+ struct retu_wdt_dev, ping_work);
+ retu_wdt_ping_enable(wdev);
+}
+
static ssize_t retu_wdt_period_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -105,7 +128,7 @@ static ssize_t retu_wdt_period_store(str
int ret;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
- retu_wdt_set_ping_timer(0);
+ retu_wdt_ping_disable(retu_wdt);
#endif
if (sscanf(buf, "%u", &new_period) != 1) {
@@ -136,30 +159,13 @@ static DEVICE_ATTR(period, S_IRUGO | S_I
retu_wdt_period_store);
static DEVICE_ATTR(counter, S_IRUGO, retu_wdt_counter_show, NULL);
-/*----------------------------------------------------------------------------*/
-
-/*
- * Since retu watchdog cannot be disabled in hardware, we must kick it
- * with a timer until userspace watchdog software takes over. Do this
- * unless /dev/watchdog is open or CONFIG_WATCHDOG_NOWAYOUT is set.
- */
-static void retu_wdt_set_ping_timer(unsigned long enable)
-{
- _retu_modify_counter(RETU_WDT_MAX_TIMER);
- if (enable)
- mod_timer(&retu_wdt->ping_timer,
- jiffies + RETU_WDT_DEFAULT_TIMER * HZ);
- else
- del_timer_sync(&retu_wdt->ping_timer);
-}
-
static int retu_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(1, (unsigned long *)&(retu_wdt->users)))
return -EBUSY;
file->private_data = (void *)retu_wdt;
- retu_wdt_set_ping_timer(0);
+ retu_wdt_ping_disable(retu_wdt);
return nonseekable_open(inode, file);
}
@@ -169,7 +175,7 @@ static int retu_wdt_release(struct inode
struct retu_wdt_dev *wdev = file->private_data;
#ifndef CONFIG_WATCHDOG_NOWAYOUT
- retu_wdt_set_ping_timer(1);
+ retu_wdt_ping_enable(retu_wdt);
#endif
wdev->users = 0;
@@ -232,7 +238,7 @@ static int __devinit retu_wdt_ping(void)
#ifdef CONFIG_WATCHDOG_NOWAYOUT
retu_modify_counter(RETU_WDT_MAX_TIMER);
#else
- retu_wdt_set_ping_timer(1);
+ retu_wdt_ping_enable(retu_wdt);
#endif
return 0;
@@ -283,7 +289,7 @@ static int __init retu_wdt_probe(struct
if (ret)
goto free3;
- setup_timer(&wdev->ping_timer, retu_wdt_set_ping_timer, 1);
+ INIT_DELAYED_WORK(&wdev->ping_work, retu_wdt_ping_work);
/* passed as module parameter? */
ret = retu_modify_counter(counter_param);
@@ -326,6 +332,7 @@ static int __devexit retu_wdt_remove(str
misc_deregister(&wdev->retu_wdt_miscdev);
device_remove_file(&pdev->dev, &dev_attr_period);
device_remove_file(&pdev->dev, &dev_attr_counter);
+ cancel_delayed_work_sync(&wdev->ping_work);
kfree(wdev);
return 0;
--
Greetings, Michael.
next reply other threads:[~2011-03-02 16:11 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-02 16:11 Michael Buesch [this message]
2011-03-03 1:33 ` [PATCH] cbus-retu-wdt: Make the watchdog driver fully preemptible Tony Lindgren
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=1299082307.13604.12.camel@marge \
--to=mb@bu3sch.de \
--cc=balbi@ti.com \
--cc=linux-omap@vger.kernel.org \
--cc=tony@atomide.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.