public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock
@ 2015-05-07 22:09 Doug Anderson
  2015-05-07 22:09 ` [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time Doug Anderson
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Doug Anderson @ 2015-05-07 22:09 UTC (permalink / raw)
  To: wim, linux; +Cc: jszhang, Doug Anderson, linux-watchdog, linux-kernel

Right now the dw_wdt uses a spinlock to protect dw_wdt_open().  The
problem is that while holding the spinlock we call:
-> dw_wdt_set_top()
   -> dw_wdt_top_in_seconds()
      -> clk_get_rate()
         -> clk_prepare_lock()
            -> mutex_lock()

Locking a mutex while holding a spinlock is not allowed and leads to
warnings like "BUG: spinlock wrong CPU on CPU#1", among other
problems.

There's no reason to use a spinlock, so switch to a mutex.

Signed-off-by: Doug Anderson <dianders@chromium.org>
---
 drivers/watchdog/dw_wdt.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index d0bb949..3fa2f19 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -30,12 +30,12 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
 #include <linux/reboot.h>
-#include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/uaccess.h>
 #include <linux/watchdog.h>
@@ -61,7 +61,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 #define WDT_TIMEOUT		(HZ / 2)
 
 static struct {
-	spinlock_t		lock;
+	struct mutex		lock;
 	void __iomem		*regs;
 	struct clk		*clk;
 	unsigned long		in_use;
@@ -177,7 +177,7 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
 	/* Make sure we don't get unloaded. */
 	__module_get(THIS_MODULE);
 
-	spin_lock(&dw_wdt.lock);
+	mutex_lock(&dw_wdt.lock);
 	if (!dw_wdt_is_enabled()) {
 		/*
 		 * The watchdog is not currently enabled. Set the timeout to
@@ -190,7 +190,7 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
 
 	dw_wdt_set_next_heartbeat();
 
-	spin_unlock(&dw_wdt.lock);
+	mutex_unlock(&dw_wdt.lock);
 
 	return nonseekable_open(inode, filp);
 }
@@ -348,7 +348,7 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	spin_lock_init(&dw_wdt.lock);
+	mutex_init(&dw_wdt.lock);
 
 	ret = misc_register(&dw_wdt_miscdev);
 	if (ret)
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time
  2015-05-07 22:09 [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Doug Anderson
@ 2015-05-07 22:09 ` Doug Anderson
  2015-05-08  1:47   ` Guenter Roeck
  2015-05-08  2:41   ` Jisheng Zhang
  2015-05-08  1:47 ` [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Guenter Roeck
  2015-05-08  2:40 ` Jisheng Zhang
  2 siblings, 2 replies; 7+ messages in thread
From: Doug Anderson @ 2015-05-07 22:09 UTC (permalink / raw)
  To: wim, linux; +Cc: jszhang, Doug Anderson, linux-watchdog, linux-kernel

If you've got code that does this in a tight loop
  1. Open watchdog
  2. Send 'expect close'
  3. Close watchdog
...you'll eventually trigger a watchdog reset.  You can reproduce this
by using daisydog (1) and running:
  while true; do daisydog -c > /dev/null; done

The problem is that each time you write to the watchdog for 'expect
close' it moves the timer .5 seconds out.  The timer thus never fires
and never pats the watchdog for you.

1: http://git.chromium.org/gitweb/?p=chromiumos/third_party/daisydog.git

Signed-off-by: Doug Anderson <dianders@chromium.org>
---
 drivers/watchdog/dw_wdt.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 3fa2f19..ff5d734 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -220,6 +220,7 @@ static ssize_t dw_wdt_write(struct file *filp, const char __user *buf,
 	}
 
 	dw_wdt_set_next_heartbeat();
+	dw_wdt_keepalive();
 	mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
 
 	return len;
-- 
2.2.0.rc0.207.ga3a616c


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock
  2015-05-07 22:09 [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Doug Anderson
  2015-05-07 22:09 ` [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time Doug Anderson
@ 2015-05-08  1:47 ` Guenter Roeck
  2015-05-08  4:01   ` Doug Anderson
  2015-05-08  2:40 ` Jisheng Zhang
  2 siblings, 1 reply; 7+ messages in thread
From: Guenter Roeck @ 2015-05-08  1:47 UTC (permalink / raw)
  To: Doug Anderson, wim; +Cc: jszhang, linux-watchdog, linux-kernel

On 05/07/2015 03:09 PM, Doug Anderson wrote:
> Right now the dw_wdt uses a spinlock to protect dw_wdt_open().  The
> problem is that while holding the spinlock we call:
> -> dw_wdt_set_top()
>     -> dw_wdt_top_in_seconds()
>        -> clk_get_rate()
>           -> clk_prepare_lock()
>              -> mutex_lock()
>
> Locking a mutex while holding a spinlock is not allowed and leads to
> warnings like "BUG: spinlock wrong CPU on CPU#1", among other
> problems.
>
> There's no reason to use a spinlock, so switch to a mutex.
>
> Signed-off-by: Doug Anderson <dianders@chromium.org>

Reviewed-by: Guenter Roeck <linux@roeck-us.net>



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time
  2015-05-07 22:09 ` [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time Doug Anderson
@ 2015-05-08  1:47   ` Guenter Roeck
  2015-05-08  2:41   ` Jisheng Zhang
  1 sibling, 0 replies; 7+ messages in thread
From: Guenter Roeck @ 2015-05-08  1:47 UTC (permalink / raw)
  To: Doug Anderson, wim; +Cc: jszhang, linux-watchdog, linux-kernel

On 05/07/2015 03:09 PM, Doug Anderson wrote:
> If you've got code that does this in a tight loop
>    1. Open watchdog
>    2. Send 'expect close'
>    3. Close watchdog
> ...you'll eventually trigger a watchdog reset.  You can reproduce this
> by using daisydog (1) and running:
>    while true; do daisydog -c > /dev/null; done
>
> The problem is that each time you write to the watchdog for 'expect
> close' it moves the timer .5 seconds out.  The timer thus never fires
> and never pats the watchdog for you.
>
> 1: http://git.chromium.org/gitweb/?p=chromiumos/third_party/daisydog.git
>
> Signed-off-by: Doug Anderson <dianders@chromium.org>

Reviewed-by: Guenter Roeck <linux@roeck-us.net>



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock
  2015-05-07 22:09 [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Doug Anderson
  2015-05-07 22:09 ` [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time Doug Anderson
  2015-05-08  1:47 ` [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Guenter Roeck
@ 2015-05-08  2:40 ` Jisheng Zhang
  2 siblings, 0 replies; 7+ messages in thread
From: Jisheng Zhang @ 2015-05-08  2:40 UTC (permalink / raw)
  To: Doug Anderson
  Cc: wim@iguana.be, linux@roeck-us.net, linux-watchdog@vger.kernel.org,
	linux-kernel@vger.kernel.org

On Thu, 7 May 2015 15:09:23 -0700
Doug Anderson <dianders@chromium.org> wrote:

> Right now the dw_wdt uses a spinlock to protect dw_wdt_open().  The
> problem is that while holding the spinlock we call:
> -> dw_wdt_set_top()
>    -> dw_wdt_top_in_seconds()
>       -> clk_get_rate()
>          -> clk_prepare_lock()
>             -> mutex_lock()
> 
> Locking a mutex while holding a spinlock is not allowed and leads to
> warnings like "BUG: spinlock wrong CPU on CPU#1", among other
> problems.
> 
> There's no reason to use a spinlock, so switch to a mutex.
> 
> Signed-off-by: Doug Anderson <dianders@chromium.org>
> ---
>  drivers/watchdog/dw_wdt.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
> index d0bb949..3fa2f19 100644
> --- a/drivers/watchdog/dw_wdt.c
> +++ b/drivers/watchdog/dw_wdt.c
> @@ -30,12 +30,12 @@
>  #include <linux/miscdevice.h>
>  #include <linux/module.h>
>  #include <linux/moduleparam.h>
> +#include <linux/mutex.h>
>  #include <linux/notifier.h>
>  #include <linux/of.h>
>  #include <linux/pm.h>
>  #include <linux/platform_device.h>
>  #include <linux/reboot.h>
> -#include <linux/spinlock.h>
>  #include <linux/timer.h>
>  #include <linux/uaccess.h>
>  #include <linux/watchdog.h>
> @@ -61,7 +61,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
>  #define WDT_TIMEOUT		(HZ / 2)
>  
>  static struct {
> -	spinlock_t		lock;
> +	struct mutex		lock;
>  	void __iomem		*regs;
>  	struct clk		*clk;
>  	unsigned long		in_use;
> @@ -177,7 +177,7 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
>  	/* Make sure we don't get unloaded. */
>  	__module_get(THIS_MODULE);
>  
> -	spin_lock(&dw_wdt.lock);
> +	mutex_lock(&dw_wdt.lock);
>  	if (!dw_wdt_is_enabled()) {
>  		/*
>  		 * The watchdog is not currently enabled. Set the timeout to
> @@ -190,7 +190,7 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
>  
>  	dw_wdt_set_next_heartbeat();
>  
> -	spin_unlock(&dw_wdt.lock);
> +	mutex_unlock(&dw_wdt.lock);
>  
>  	return nonseekable_open(inode, filp);
>  }
> @@ -348,7 +348,7 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	spin_lock_init(&dw_wdt.lock);
> +	mutex_init(&dw_wdt.lock);
>  
>  	ret = misc_register(&dw_wdt_miscdev);
>  	if (ret)

Tested on marvell BG2Q SoC, no issue found. So

Tested-by: Jisheng Zhang <jszhang@marvell.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time
  2015-05-07 22:09 ` [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time Doug Anderson
  2015-05-08  1:47   ` Guenter Roeck
@ 2015-05-08  2:41   ` Jisheng Zhang
  1 sibling, 0 replies; 7+ messages in thread
From: Jisheng Zhang @ 2015-05-08  2:41 UTC (permalink / raw)
  To: Doug Anderson, wim@iguana.be, linux@roeck-us.net
  Cc: linux-watchdog@vger.kernel.org, linux-kernel@vger.kernel.org

On Thu, 7 May 2015 15:09:24 -0700
Doug Anderson <dianders@chromium.org> wrote:

> If you've got code that does this in a tight loop
>   1. Open watchdog
>   2. Send 'expect close'
>   3. Close watchdog
> ...you'll eventually trigger a watchdog reset.  You can reproduce this
> by using daisydog (1) and running:
>   while true; do daisydog -c > /dev/null; done
> 
> The problem is that each time you write to the watchdog for 'expect
> close' it moves the timer .5 seconds out.  The timer thus never fires
> and never pats the watchdog for you.
> 
> 1: http://git.chromium.org/gitweb/?p=chromiumos/third_party/daisydog.git
> 
> Signed-off-by: Doug Anderson <dianders@chromium.org>
> ---
>  drivers/watchdog/dw_wdt.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
> index 3fa2f19..ff5d734 100644
> --- a/drivers/watchdog/dw_wdt.c
> +++ b/drivers/watchdog/dw_wdt.c
> @@ -220,6 +220,7 @@ static ssize_t dw_wdt_write(struct file *filp, const char __user *buf,
>  	}
>  
>  	dw_wdt_set_next_heartbeat();
> +	dw_wdt_keepalive();
>  	mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
>  
>  	return len;

Tested-by: Jisheng Zhang <jszhang@marvell.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock
  2015-05-08  1:47 ` [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Guenter Roeck
@ 2015-05-08  4:01   ` Doug Anderson
  0 siblings, 0 replies; 7+ messages in thread
From: Doug Anderson @ 2015-05-08  4:01 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Wim Van Sebroeck, Jisheng Zhang, linux-watchdog@vger.kernel.org,
	linux-kernel@vger.kernel.org, Dmitry Torokhov

Hi,

On Thu, May 7, 2015 at 6:47 PM, Guenter Roeck <linux@roeck-us.net> wrote:
> On 05/07/2015 03:09 PM, Doug Anderson wrote:
>>
>> Right now the dw_wdt uses a spinlock to protect dw_wdt_open().  The
>> problem is that while holding the spinlock we call:
>> -> dw_wdt_set_top()
>>     -> dw_wdt_top_in_seconds()
>>        -> clk_get_rate()
>>           -> clk_prepare_lock()
>>              -> mutex_lock()
>>
>> Locking a mutex while holding a spinlock is not allowed and leads to
>> warnings like "BUG: spinlock wrong CPU on CPU#1", among other
>> problems.
>>
>> There's no reason to use a spinlock, so switch to a mutex.
>>
>> Signed-off-by: Doug Anderson <dianders@chromium.org>
>
>
> Reviewed-by: Guenter Roeck <linux@roeck-us.net>

As Dmitry pointed out in another context, and even better fix is to
just remove the spinlock altogether.  I'll send up v2...

-Doug

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-05-08  4:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-07 22:09 [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Doug Anderson
2015-05-07 22:09 ` [PATCH 2/2] watchdog: dw_wdt: keepalive the watchdog at write time Doug Anderson
2015-05-08  1:47   ` Guenter Roeck
2015-05-08  2:41   ` Jisheng Zhang
2015-05-08  1:47 ` [PATCH 1/2] watchdog: dw_wdt: Use a mutex, not a spinlock Guenter Roeck
2015-05-08  4:01   ` Doug Anderson
2015-05-08  2:40 ` Jisheng Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox