From patchwork Wed Mar 2 16:11:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Buesch X-Patchwork-Id: 603201 X-Patchwork-Delegate: tony@atomide.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p22GBxsu019105 for ; Wed, 2 Mar 2011 16:11:59 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751940Ab1CBQL4 (ORCPT ); Wed, 2 Mar 2011 11:11:56 -0500 Received: from 80-190-117-144.ip-home.de ([80.190.117.144]:45227 "EHLO bu3sch.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752002Ab1CBQLx (ORCPT ); Wed, 2 Mar 2011 11:11:53 -0500 Received: by bu3sch.de with esmtpsa (Exim 4.69) (envelope-from ) id 1PuoeV-0002Jg-Km; Wed, 02 Mar 2011 17:11:51 +0100 Subject: [PATCH] cbus-retu-wdt: Make the watchdog driver fully preemptible From: Michael Buesch To: Tony Lindgren Cc: Felipe Balbi , linux-omap Date: Wed, 02 Mar 2011 17:11:47 +0100 Message-ID: <1299082307.13604.12.camel@marge> Mime-Version: 1.0 X-Mailer: Evolution 2.30.3 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Wed, 02 Mar 2011 16:11:59 +0000 (UTC) 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;