diff mbox

[v3,4/6] watchdog: sp805: set WDOG_HW_RUNNING when appropriate

Message ID 1527120924-12131-5-git-send-email-ray.jui@broadcom.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ray Jui May 24, 2018, 12:15 a.m. UTC
If the watchdog hardware is already enabled during the boot process,
when the Linux watchdog driver loads, it should reset the watchdog and
tell the watchdog framework. As a result, ping can be generated from
the watchdog framework, until the userspace watchdog daemon takes over
control

Signed-off-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
---
 drivers/watchdog/sp805_wdt.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

Comments

Guenter Roeck May 24, 2018, 4:19 p.m. UTC | #1
On Wed, May 23, 2018 at 05:15:22PM -0700, Ray Jui wrote:
> If the watchdog hardware is already enabled during the boot process,
> when the Linux watchdog driver loads, it should reset the watchdog and
> tell the watchdog framework. As a result, ping can be generated from
> the watchdog framework, until the userspace watchdog daemon takes over
> control
> 
> Signed-off-by: Ray Jui <ray.jui@broadcom.com>
> Reviewed-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> Reviewed-by: Scott Branden <scott.branden@broadcom.com>

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

I have one question, though: Is it really correct that both
INT_ENABLE _and_ RESET_ENABLE have to be set to enable the watdog ?
What if only RESET_ENABLE is set ?

Thanks,
Guenter

> ---
>  drivers/watchdog/sp805_wdt.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
> index 1484609..d662a6f 100644
> --- a/drivers/watchdog/sp805_wdt.c
> +++ b/drivers/watchdog/sp805_wdt.c
> @@ -42,6 +42,7 @@
>  	/* control register masks */
>  	#define	INT_ENABLE	(1 << 0)
>  	#define	RESET_ENABLE	(1 << 1)
> +	#define	ENABLE_MASK	(INT_ENABLE | RESET_ENABLE)
>  #define WDTINTCLR		0x00C
>  #define WDTRIS			0x010
>  #define WDTMIS			0x014
> @@ -74,6 +75,15 @@ module_param(nowayout, bool, 0);
>  MODULE_PARM_DESC(nowayout,
>  		"Set to 1 to keep watchdog running after device release");
>  
> +/* returns true if wdt is running; otherwise returns false */
> +static bool wdt_is_running(struct watchdog_device *wdd)
> +{
> +	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
> +	u32 wdtcontrol = readl_relaxed(wdt->base + WDTCONTROL);
> +
> +	return (wdtcontrol & ENABLE_MASK) == ENABLE_MASK;
> +}
> +
>  /* This routine finds load value that will reset system in required timout */
>  static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
>  {
> @@ -239,6 +249,15 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
>  	watchdog_init_timeout(&wdt->wdd, 0, &adev->dev);
>  	wdt_setload(&wdt->wdd, wdt->wdd.timeout);
>  
> +	/*
> +	 * If HW is already running, enable/reset the wdt and set the running
> +	 * bit to tell the wdt subsystem
> +	 */
> +	if (wdt_is_running(&wdt->wdd)) {
> +		wdt_enable(&wdt->wdd);
> +		set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
> +	}
> +
>  	ret = watchdog_register_device(&wdt->wdd);
>  	if (ret) {
>  		dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
> -- 
> 2.1.4
> 
> --
> 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
Ray Jui May 24, 2018, 4:36 p.m. UTC | #2
On 5/24/2018 9:19 AM, Guenter Roeck wrote:
> On Wed, May 23, 2018 at 05:15:22PM -0700, Ray Jui wrote:
>> If the watchdog hardware is already enabled during the boot process,
>> when the Linux watchdog driver loads, it should reset the watchdog and
>> tell the watchdog framework. As a result, ping can be generated from
>> the watchdog framework, until the userspace watchdog daemon takes over
>> control
>>
>> Signed-off-by: Ray Jui <ray.jui@broadcom.com>
>> Reviewed-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
>> Reviewed-by: Scott Branden <scott.branden@broadcom.com>
> 
> Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> 
> I have one question, though: Is it really correct that both
> INT_ENABLE _and_ RESET_ENABLE have to be set to enable the watdog ?
> What if only RESET_ENABLE is set ?

According to the SP805 TRM, INT_ENABLE needs to be set to high to enable 
the counter and the interrupt. Counter will be stopped if INT_ENABLE is 
cleared. So yes, INT_ENABLE needs to be set.

Thanks,

Ray

> 
> Thanks,
> Guenter
> 
>> ---
>>   drivers/watchdog/sp805_wdt.c | 19 +++++++++++++++++++
>>   1 file changed, 19 insertions(+)
>>
>> diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
>> index 1484609..d662a6f 100644
>> --- a/drivers/watchdog/sp805_wdt.c
>> +++ b/drivers/watchdog/sp805_wdt.c
>> @@ -42,6 +42,7 @@
>>   	/* control register masks */
>>   	#define	INT_ENABLE	(1 << 0)
>>   	#define	RESET_ENABLE	(1 << 1)
>> +	#define	ENABLE_MASK	(INT_ENABLE | RESET_ENABLE)
>>   #define WDTINTCLR		0x00C
>>   #define WDTRIS			0x010
>>   #define WDTMIS			0x014
>> @@ -74,6 +75,15 @@ module_param(nowayout, bool, 0);
>>   MODULE_PARM_DESC(nowayout,
>>   		"Set to 1 to keep watchdog running after device release");
>>   
>> +/* returns true if wdt is running; otherwise returns false */
>> +static bool wdt_is_running(struct watchdog_device *wdd)
>> +{
>> +	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
>> +	u32 wdtcontrol = readl_relaxed(wdt->base + WDTCONTROL);
>> +
>> +	return (wdtcontrol & ENABLE_MASK) == ENABLE_MASK;
>> +}
>> +
>>   /* This routine finds load value that will reset system in required timout */
>>   static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
>>   {
>> @@ -239,6 +249,15 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
>>   	watchdog_init_timeout(&wdt->wdd, 0, &adev->dev);
>>   	wdt_setload(&wdt->wdd, wdt->wdd.timeout);
>>   
>> +	/*
>> +	 * If HW is already running, enable/reset the wdt and set the running
>> +	 * bit to tell the wdt subsystem
>> +	 */
>> +	if (wdt_is_running(&wdt->wdd)) {
>> +		wdt_enable(&wdt->wdd);
>> +		set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
>> +	}
>> +
>>   	ret = watchdog_register_device(&wdt->wdd);
>>   	if (ret) {
>>   		dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
>> -- 
>> 2.1.4
>>
>> --
>> 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
Guenter Roeck May 24, 2018, 5:11 p.m. UTC | #3
On Thu, May 24, 2018 at 09:36:25AM -0700, Ray Jui wrote:
> 
> 
> On 5/24/2018 9:19 AM, Guenter Roeck wrote:
> >On Wed, May 23, 2018 at 05:15:22PM -0700, Ray Jui wrote:
> >>If the watchdog hardware is already enabled during the boot process,
> >>when the Linux watchdog driver loads, it should reset the watchdog and
> >>tell the watchdog framework. As a result, ping can be generated from
> >>the watchdog framework, until the userspace watchdog daemon takes over
> >>control
> >>
> >>Signed-off-by: Ray Jui <ray.jui@broadcom.com>
> >>Reviewed-by: Vladimir Olovyannikov <vladimir.olovyannikov@broadcom.com>
> >>Reviewed-by: Scott Branden <scott.branden@broadcom.com>
> >
> >Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> >
> >I have one question, though: Is it really correct that both
> >INT_ENABLE _and_ RESET_ENABLE have to be set to enable the watdog ?
> >What if only RESET_ENABLE is set ?
> 
> According to the SP805 TRM, INT_ENABLE needs to be set to high to enable the
> counter and the interrupt. Counter will be stopped if INT_ENABLE is cleared.
> So yes, INT_ENABLE needs to be set.
> 
Excellent, thanks for the clarification.

Guenter
diff mbox

Patch

diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 1484609..d662a6f 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -42,6 +42,7 @@ 
 	/* control register masks */
 	#define	INT_ENABLE	(1 << 0)
 	#define	RESET_ENABLE	(1 << 1)
+	#define	ENABLE_MASK	(INT_ENABLE | RESET_ENABLE)
 #define WDTINTCLR		0x00C
 #define WDTRIS			0x010
 #define WDTMIS			0x014
@@ -74,6 +75,15 @@  module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout,
 		"Set to 1 to keep watchdog running after device release");
 
+/* returns true if wdt is running; otherwise returns false */
+static bool wdt_is_running(struct watchdog_device *wdd)
+{
+	struct sp805_wdt *wdt = watchdog_get_drvdata(wdd);
+	u32 wdtcontrol = readl_relaxed(wdt->base + WDTCONTROL);
+
+	return (wdtcontrol & ENABLE_MASK) == ENABLE_MASK;
+}
+
 /* This routine finds load value that will reset system in required timout */
 static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
 {
@@ -239,6 +249,15 @@  sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
 	watchdog_init_timeout(&wdt->wdd, 0, &adev->dev);
 	wdt_setload(&wdt->wdd, wdt->wdd.timeout);
 
+	/*
+	 * If HW is already running, enable/reset the wdt and set the running
+	 * bit to tell the wdt subsystem
+	 */
+	if (wdt_is_running(&wdt->wdd)) {
+		wdt_enable(&wdt->wdd);
+		set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
+	}
+
 	ret = watchdog_register_device(&wdt->wdd);
 	if (ret) {
 		dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",