linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] watchdog: dw_wdt: one bug fix and restart handler support
@ 2014-09-23  7:42 Jisheng Zhang
  2014-09-23  7:42 ` [PATCH v2 1/2] watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top() Jisheng Zhang
  2014-09-23  7:42 ` [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support Jisheng Zhang
  0 siblings, 2 replies; 7+ messages in thread
From: Jisheng Zhang @ 2014-09-23  7:42 UTC (permalink / raw)
  To: wim, linux; +Cc: linux-watchdog, linux-kernel, linux-arm-kernel, Jisheng Zhang

These patches are intend to improve dw_wdt in the following two aspects:

Firstly, the TOP_INIT, ie bit 4-7 of the WDOG_TIMEOUT_RANGE_REG_OFFSET register
may be zero at reset on some HW, so the timeout period may be very short, thus
we will see immediate system reset after openning the watchdog. Fix this
problem by also initialising the TOP_INIT when setting TOP.

Secondly, the WDT can also be used to reboot the system with the help of
recently introduced restart handler.

Tested on Marvell BG2Q DMP board.

Changes since v1:
  - add some wait to let the reset catch, suggested by Guenter Roeck
  - setting TOP_INIT as well when setting TOP in function dw_wdt_set_top to
    fix the reboot soon issue.

Jisheng Zhang (2):
  watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top()
  watchdog: dw_wdt: add restart handler support

 drivers/watchdog/dw_wdt.c | 36 +++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

-- 
2.1.0


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

* [PATCH v2 1/2] watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top()
  2014-09-23  7:42 [PATCH v2 0/2] watchdog: dw_wdt: one bug fix and restart handler support Jisheng Zhang
@ 2014-09-23  7:42 ` Jisheng Zhang
  2014-09-23 18:27   ` Guenter Roeck
  2014-09-23  7:42 ` [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support Jisheng Zhang
  1 sibling, 1 reply; 7+ messages in thread
From: Jisheng Zhang @ 2014-09-23  7:42 UTC (permalink / raw)
  To: wim, linux; +Cc: linux-watchdog, linux-kernel, linux-arm-kernel, Jisheng Zhang

The TOP_INIT, ie bit 4-7 of the WDOG_TIMEOUT_RANGE_REG_OFFSET register
may be zero, so the timeout period may be very short after initialization
is done, thus the system may be reset soon after enabling. We fix this
problem by also initialising the TOP_INIT when setting TOP in function
dw_wdt_set_top().

Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
---
 drivers/watchdog/dw_wdt.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 9f21029..449c885 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -40,6 +40,7 @@
 #define WDOG_CONTROL_REG_OFFSET		    0x00
 #define WDOG_CONTROL_REG_WDT_EN_MASK	    0x01
 #define WDOG_TIMEOUT_RANGE_REG_OFFSET	    0x04
+#define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT    4
 #define WDOG_CURRENT_COUNT_REG_OFFSET	    0x08
 #define WDOG_COUNTER_RESTART_REG_OFFSET     0x0c
 #define WDOG_COUNTER_RESTART_KICK_VALUE	    0x76
@@ -106,7 +107,8 @@ static int dw_wdt_set_top(unsigned top_s)
 		}
 
 	/* Set the new value in the watchdog. */
-	writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
+	writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT,
+		dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
 
 	dw_wdt_set_next_heartbeat();
 
-- 
2.1.0


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

* [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support
  2014-09-23  7:42 [PATCH v2 0/2] watchdog: dw_wdt: one bug fix and restart handler support Jisheng Zhang
  2014-09-23  7:42 ` [PATCH v2 1/2] watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top() Jisheng Zhang
@ 2014-09-23  7:42 ` Jisheng Zhang
  2014-09-23 18:31   ` Guenter Roeck
  1 sibling, 1 reply; 7+ messages in thread
From: Jisheng Zhang @ 2014-09-23  7:42 UTC (permalink / raw)
  To: wim, linux; +Cc: linux-watchdog, linux-kernel, linux-arm-kernel, Jisheng Zhang

The kernel core now provides an API to trigger a system restart.
Register with it to support restarting the system via. watchdog.

Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
---
 drivers/watchdog/dw_wdt.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index 449c885..9e577a6 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -21,6 +21,7 @@
 
 #include <linux/bitops.h>
 #include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/fs.h>
@@ -29,9 +30,11 @@
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.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>
@@ -63,6 +66,7 @@ static struct {
 	unsigned long		next_heartbeat;
 	struct timer_list	timer;
 	int			expect_close;
+	struct notifier_block	restart_handler;
 } dw_wdt;
 
 static inline int dw_wdt_is_enabled(void)
@@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void)
 	       WDOG_COUNTER_RESTART_REG_OFFSET);
 }
 
+static int dw_wdt_restart_handle(struct notifier_block *this,
+				unsigned long mode, void *cmd)
+{
+	u32 val;
+
+	writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
+	val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
+	if (val & WDOG_CONTROL_REG_WDT_EN_MASK)
+		writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
+			WDOG_COUNTER_RESTART_REG_OFFSET);
+	else
+		writel(WDOG_CONTROL_REG_WDT_EN_MASK,
+		       dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
+
+	/* wait for reset to assert... */
+	mdelay(500);
+
+	return NOTIFY_DONE;
+}
+
 static void dw_wdt_ping(unsigned long data)
 {
 	if (time_before(jiffies, dw_wdt.next_heartbeat) ||
@@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
 	if (ret)
 		goto out_disable_clk;
 
+	dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle;
+	dw_wdt.restart_handler.priority = 128;
+	ret = register_restart_handler(&dw_wdt.restart_handler);
+	if (ret)
+		pr_warn("cannot register restart handler\n");
+
 	dw_wdt_set_next_heartbeat();
 	setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
 	mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
@@ -330,6 +360,8 @@ out_disable_clk:
 
 static int dw_wdt_drv_remove(struct platform_device *pdev)
 {
+	unregister_restart_handler(&dw_wdt.restart_handler);
+
 	misc_deregister(&dw_wdt_miscdev);
 
 	clk_disable_unprepare(dw_wdt.clk);
-- 
2.1.0


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

* Re: [PATCH v2 1/2] watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top()
  2014-09-23  7:42 ` [PATCH v2 1/2] watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top() Jisheng Zhang
@ 2014-09-23 18:27   ` Guenter Roeck
  0 siblings, 0 replies; 7+ messages in thread
From: Guenter Roeck @ 2014-09-23 18:27 UTC (permalink / raw)
  To: Jisheng Zhang; +Cc: wim, linux-watchdog, linux-kernel, linux-arm-kernel

On Tue, Sep 23, 2014 at 03:42:11PM +0800, Jisheng Zhang wrote:
> The TOP_INIT, ie bit 4-7 of the WDOG_TIMEOUT_RANGE_REG_OFFSET register
> may be zero, so the timeout period may be very short after initialization
> is done, thus the system may be reset soon after enabling. We fix this
> problem by also initialising the TOP_INIT when setting TOP in function
> dw_wdt_set_top().
> 
> Signed-off-by: Jisheng Zhang <jszhang@marvell.com>

That should do it.

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

> ---
>  drivers/watchdog/dw_wdt.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
> index 9f21029..449c885 100644
> --- a/drivers/watchdog/dw_wdt.c
> +++ b/drivers/watchdog/dw_wdt.c
> @@ -40,6 +40,7 @@
>  #define WDOG_CONTROL_REG_OFFSET		    0x00
>  #define WDOG_CONTROL_REG_WDT_EN_MASK	    0x01
>  #define WDOG_TIMEOUT_RANGE_REG_OFFSET	    0x04
> +#define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT    4
>  #define WDOG_CURRENT_COUNT_REG_OFFSET	    0x08
>  #define WDOG_COUNTER_RESTART_REG_OFFSET     0x0c
>  #define WDOG_COUNTER_RESTART_KICK_VALUE	    0x76
> @@ -106,7 +107,8 @@ static int dw_wdt_set_top(unsigned top_s)
>  		}
>  
>  	/* Set the new value in the watchdog. */
> -	writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
> +	writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT,
> +		dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
>  
>  	dw_wdt_set_next_heartbeat();
>  
> -- 
> 2.1.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support
  2014-09-23  7:42 ` [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support Jisheng Zhang
@ 2014-09-23 18:31   ` Guenter Roeck
  2014-09-24  1:11     ` Jisheng Zhang
  0 siblings, 1 reply; 7+ messages in thread
From: Guenter Roeck @ 2014-09-23 18:31 UTC (permalink / raw)
  To: Jisheng Zhang; +Cc: wim, linux-watchdog, linux-kernel, linux-arm-kernel

On Tue, Sep 23, 2014 at 03:42:12PM +0800, Jisheng Zhang wrote:
> The kernel core now provides an API to trigger a system restart.
> Register with it to support restarting the system via. watchdog.
> 
> Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
> ---
>  drivers/watchdog/dw_wdt.c | 32 ++++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
> 
> diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
> index 449c885..9e577a6 100644
> --- a/drivers/watchdog/dw_wdt.c
> +++ b/drivers/watchdog/dw_wdt.c
> @@ -21,6 +21,7 @@
>  
>  #include <linux/bitops.h>
>  #include <linux/clk.h>
> +#include <linux/delay.h>
>  #include <linux/device.h>
>  #include <linux/err.h>
>  #include <linux/fs.h>
> @@ -29,9 +30,11 @@
>  #include <linux/miscdevice.h>
>  #include <linux/module.h>
>  #include <linux/moduleparam.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>
> @@ -63,6 +66,7 @@ static struct {
>  	unsigned long		next_heartbeat;
>  	struct timer_list	timer;
>  	int			expect_close;
> +	struct notifier_block	restart_handler;
>  } dw_wdt;
>  
>  static inline int dw_wdt_is_enabled(void)
> @@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void)
>  	       WDOG_COUNTER_RESTART_REG_OFFSET);
>  }
>  
> +static int dw_wdt_restart_handle(struct notifier_block *this,
> +				unsigned long mode, void *cmd)
> +{
> +	u32 val;
> +
> +	writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
> +	val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
> +	if (val & WDOG_CONTROL_REG_WDT_EN_MASK)
> +		writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
> +			WDOG_COUNTER_RESTART_REG_OFFSET);
> +	else
> +		writel(WDOG_CONTROL_REG_WDT_EN_MASK,
> +		       dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
> +
> +	/* wait for reset to assert... */
> +	mdelay(500);
> +
> +	return NOTIFY_DONE;
> +}
> +
>  static void dw_wdt_ping(unsigned long data)
>  {
>  	if (time_before(jiffies, dw_wdt.next_heartbeat) ||
> @@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto out_disable_clk;
>  
> +	dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle;
> +	dw_wdt.restart_handler.priority = 128;
> +	ret = register_restart_handler(&dw_wdt.restart_handler);
> +	if (ret)
> +		pr_warn("cannot register restart handler\n");

Please use dev_warn(&pdev->dev, ...).

Thanks,
Guenter

> +
>  	dw_wdt_set_next_heartbeat();
>  	setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
>  	mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
> @@ -330,6 +360,8 @@ out_disable_clk:
>  
>  static int dw_wdt_drv_remove(struct platform_device *pdev)
>  {
> +	unregister_restart_handler(&dw_wdt.restart_handler);
> +
>  	misc_deregister(&dw_wdt_miscdev);
>  
>  	clk_disable_unprepare(dw_wdt.clk);
> -- 
> 2.1.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support
  2014-09-23 18:31   ` Guenter Roeck
@ 2014-09-24  1:11     ` Jisheng Zhang
  2014-09-24  1:40       ` Guenter Roeck
  0 siblings, 1 reply; 7+ messages in thread
From: Jisheng Zhang @ 2014-09-24  1:11 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: wim, linux-watchdog, linux-kernel, linux-arm-kernel

Dear Guenter,

On Tue, 23 Sep 2014 11:31:59 -0700
Guenter Roeck <linux@roeck-us.net> wrote:

> On Tue, Sep 23, 2014 at 03:42:12PM +0800, Jisheng Zhang wrote:
> > The kernel core now provides an API to trigger a system restart.
> > Register with it to support restarting the system via. watchdog.
> > 
> > Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
> > ---
> >  drivers/watchdog/dw_wdt.c | 32 ++++++++++++++++++++++++++++++++
> >  1 file changed, 32 insertions(+)
> > 
> > diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
> > index 449c885..9e577a6 100644
> > --- a/drivers/watchdog/dw_wdt.c
> > +++ b/drivers/watchdog/dw_wdt.c
> > @@ -21,6 +21,7 @@
> >  
> >  #include <linux/bitops.h>
> >  #include <linux/clk.h>
> > +#include <linux/delay.h>
> >  #include <linux/device.h>
> >  #include <linux/err.h>
> >  #include <linux/fs.h>
> > @@ -29,9 +30,11 @@
> >  #include <linux/miscdevice.h>
> >  #include <linux/module.h>
> >  #include <linux/moduleparam.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>
> > @@ -63,6 +66,7 @@ static struct {
> >  	unsigned long		next_heartbeat;
> >  	struct timer_list	timer;
> >  	int			expect_close;
> > +	struct notifier_block	restart_handler;
> >  } dw_wdt;
> >  
> >  static inline int dw_wdt_is_enabled(void)
> > @@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void)
> >  	       WDOG_COUNTER_RESTART_REG_OFFSET);
> >  }
> >  
> > +static int dw_wdt_restart_handle(struct notifier_block *this,
> > +				unsigned long mode, void *cmd)
> > +{
> > +	u32 val;
> > +
> > +	writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
> > +	val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
> > +	if (val & WDOG_CONTROL_REG_WDT_EN_MASK)
> > +		writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
> > +			WDOG_COUNTER_RESTART_REG_OFFSET);
> > +	else
> > +		writel(WDOG_CONTROL_REG_WDT_EN_MASK,
> > +		       dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
> > +
> > +	/* wait for reset to assert... */
> > +	mdelay(500);
> > +
> > +	return NOTIFY_DONE;
> > +}
> > +
> >  static void dw_wdt_ping(unsigned long data)
> >  {
> >  	if (time_before(jiffies, dw_wdt.next_heartbeat) ||
> > @@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device
> > *pdev) if (ret)
> >  		goto out_disable_clk;
> >  
> > +	dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle;
> > +	dw_wdt.restart_handler.priority = 128;
> > +	ret = register_restart_handler(&dw_wdt.restart_handler);
> > +	if (ret)
> > +		pr_warn("cannot register restart handler\n");
> 
> Please use dev_warn(&pdev->dev, ...).

Yep, that's what I thought when patching the code. But the original source is
using pr_*(), so I use pr_warn() to keep unification. Is there any better
solution?

Thanks for your review,
Jisheng

> 
> Thanks,
> Guenter
> 
> > +
> >  	dw_wdt_set_next_heartbeat();
> >  	setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
> >  	mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
> > @@ -330,6 +360,8 @@ out_disable_clk:
> >  
> >  static int dw_wdt_drv_remove(struct platform_device *pdev)
> >  {
> > +	unregister_restart_handler(&dw_wdt.restart_handler);
> > +
> >  	misc_deregister(&dw_wdt_miscdev);
> >  
> >  	clk_disable_unprepare(dw_wdt.clk);
> > -- 
> > 2.1.0
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-watchdog"
> > in the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

* Re: [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support
  2014-09-24  1:11     ` Jisheng Zhang
@ 2014-09-24  1:40       ` Guenter Roeck
  0 siblings, 0 replies; 7+ messages in thread
From: Guenter Roeck @ 2014-09-24  1:40 UTC (permalink / raw)
  To: Jisheng Zhang; +Cc: wim, linux-watchdog, linux-kernel, linux-arm-kernel

On 09/23/2014 06:11 PM, Jisheng Zhang wrote:
[ ... ]
>>> +	dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle;
>>> +	dw_wdt.restart_handler.priority = 128;
>>> +	ret = register_restart_handler(&dw_wdt.restart_handler);
>>> +	if (ret)
>>> +		pr_warn("cannot register restart handler\n");
>>
>> Please use dev_warn(&pdev->dev, ...).
>
> Yep, that's what I thought when patching the code. But the original source is
> using pr_*(), so I use pr_warn() to keep unification. Is there any better
> solution?
>

Good point. Makes sense, then, to leave that as cleanup.

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


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

end of thread, other threads:[~2014-09-24  1:41 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-23  7:42 [PATCH v2 0/2] watchdog: dw_wdt: one bug fix and restart handler support Jisheng Zhang
2014-09-23  7:42 ` [PATCH v2 1/2] watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top() Jisheng Zhang
2014-09-23 18:27   ` Guenter Roeck
2014-09-23  7:42 ` [PATCH v2 2/2] watchdog: dw_wdt: add restart handler support Jisheng Zhang
2014-09-23 18:31   ` Guenter Roeck
2014-09-24  1:11     ` Jisheng Zhang
2014-09-24  1:40       ` Guenter Roeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).