Hi Raffaele,

On Monday 29 October 2012 04:41 PM, Raffaele Recalcati wrote:
In NOWAYOUT case it is better to have watchdog always enabled at boot,
in order not to leave the system in undefined state in case of userspace
failure.

Signed-off-by: Raffaele Recalcati <[email protected]>
---
Tested using http://arago-project.org/git/projects/linux-omap3.git
v2.6.37_OMAPPSP_04.02.00.07 commit.

  drivers/watchdog/omap_wdt.c |    8 ++++++++
  1 file changed, 8 insertions(+)

diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 27ab8db..181b939 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -304,8 +304,16 @@ static int __devinit omap_wdt_probe(struct platform_device 
*pdev)
        pm_runtime_enable(wdev->dev);
        pm_runtime_get_sync(wdev->dev);

+#ifndef CONFIG_WATCHDOG_NOWAYOUT
        omap_wdt_disable(wdev);
        omap_wdt_adjust_timeout(timer_margin);
+#else
+       omap_wdt_adjust_timeout(timer_margin);
+       omap_wdt_disable(wdev);
+       omap_wdt_set_timeout(wdev);
+       omap_wdt_enable(wdev);
+       omap_wdt_ping(wdev);
IMHO this is not the correct procedure to start the watchdog.
The sequence to start watchdog is something similar in omap_wdt_open()
the steps are:
1) Increment omap_wdt_users
2) Set prescalar value
3) Enable prescalar value
4) Load timer counter value
5) Enable watchdog timer.

In your case you are missing first 3 steps.

After starting the watchdog, there should be some daemon
which pets the watchdog before timeout, if not it will reset the board.
This is also missing in your case.
( This daemon can be achieved by enabling delay interrupt and period)

And there is a pm_runtime_put_sync after you enable your watchdog.
Because of which you get the following warning
omap_hwmod: wd_timer2: _wait_target_disable failed

Below is the patch which might meet your aims.
Please comment on the patch.

Here I enabled delay interrupt and delay period
for petting watchdog before timeout.
watchdog is enabled for all the cases(not only for NOWAYOUT)



Signed-off-by: Lokesh Vutla <[email protected]>
---
drivers/watchdog/omap_wdt.c | 82 ++++++++++++++++++++++++++++++++++++++++-----
 drivers/watchdog/omap_wdt.h |  4 +++
 2 files changed, 78 insertions(+), 8 deletions(-)

diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index f5db18db..38e36c1 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -45,6 +45,7 @@
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
 #include <mach/hardware.h>
 #include <plat/cpu.h>
 #include <plat/prcm.h>
@@ -57,6 +58,10 @@ static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");

+static int kernelpet = 1;
+module_param(kernelpet, int, 0);
+MODULE_PARM_DESC(kernelpet, "pet watchdog in kernel via irq");
+
 static unsigned int wdt_trgr_pattern = 0x1234;
 static DEFINE_SPINLOCK(wdt_lock);

@@ -66,6 +71,7 @@ struct omap_wdt_dev {
        int             omap_wdt_users;
        struct resource *mem;
        struct miscdevice omap_wdt_miscdev;
+       int irq;
 };

 static void omap_wdt_ping(struct omap_wdt_dev *wdev)
@@ -125,6 +131,7 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
 static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
 {
        u32 pre_margin = GET_WLDR_VAL(timer_margin);
+       u32 delay_period = GET_WLDR_VAL(timer_margin / 2);
        void __iomem *base = wdev->base;

        /* just count up at 32 KHz */
@@ -134,14 +141,29 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
        __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
        while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
+
+       /* Set delay interrupt to half the watchdog interval. */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 1 << 5)
+               cpu_relax();
+       __raw_writel(delay_period, base + OMAP_WATCHDOG_WDLY);
 }

-/*
- *     Allow only one task to hold it open
- */
-static int omap_wdt_open(struct inode *inode, struct file *file)
+static irqreturn_t omap_wdt_interrupt(int irq, void *dev_id)
+{
+       struct omap_wdt_dev *wdev = dev_id;
+       void __iomem *base = wdev->base;
+       u32 i;
+
+       i = __raw_readl(base + OMAP_WATCHDOG_WIRQSTAT);
+       __raw_writel(i, base + OMAP_WATCHDOG_WIRQSTAT);
+
+       omap_wdt_ping(wdev);
+
+       return IRQ_HANDLED;
+}
+
+static int omap_wdt_setup(struct omap_wdt_dev *wdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
        void __iomem *base = wdev->base;

        if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
@@ -157,12 +179,31 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
        while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();

-       file->private_data = (void *) wdev;
-
        omap_wdt_set_timeout(wdev);
        omap_wdt_ping(wdev); /* trigger loading of new timeout value */
+
+       /* Enable delay interrupt */
+       if (kernelpet && wdev->irq)
+               __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENSET);
+
        omap_wdt_enable(wdev);

+       return 0;
+}
+/*
+ *     Allow only one task to hold it open
+ */
+static int omap_wdt_open(struct inode *inode, struct file *file)
+{
+       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+       int ret;
+
+       ret = omap_wdt_setup(wdev);
+
+       if (ret)
+               return ret;
+
+       file->private_data = (void *)wdev;
        return nonseekable_open(inode, file);
 }

@@ -176,6 +217,10 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
        omap_wdt_disable(wdev);

+       /* Disable delay interrupt */
+       if (kernelpet && wdev->irq)
+               __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENCLR);
+
        pm_runtime_put_sync(wdev->dev);
 #else
        pr_crit("Unexpected close, not stopping!\n");
@@ -266,7 +311,7 @@ static const struct file_operations omap_wdt_fops = {

 static int __devinit omap_wdt_probe(struct platform_device *pdev)
 {
-       struct resource *res, *mem;
+       struct resource *res, *mem, *res_irq;
        struct omap_wdt_dev *wdev;
        int ret;

@@ -288,6 +333,8 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
                goto err_busy;
        }

+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
        wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
        if (!wdev) {
                ret = -ENOMEM;
@@ -304,6 +351,16 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
                goto err_ioremap;
        }

+       if (res_irq) {
+               ret = request_irq(res_irq->start, omap_wdt_interrupt, 0,
+                                 dev_name(&pdev->dev), wdev);
+
+               if (ret)
+                       goto err_irq;
+
+               wdev->irq = res_irq->start;
+       }
+
        platform_set_drvdata(pdev, wdev);

        pm_runtime_enable(wdev->dev);
@@ -329,11 +386,17 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)

        omap_wdt_dev = pdev;

+       if (kernelpet && wdev->irq)
+               return  omap_wdt_setup(wdev);
+
        return 0;

 err_misc:
        pm_runtime_disable(wdev->dev);
        platform_set_drvdata(pdev, NULL);
+       if (wdev->irq)
+               free_irq(wdev->irq, wdev);
+err_irq:
        iounmap(wdev->base);

 err_ioremap:
@@ -372,6 +435,9 @@ static int __devexit omap_wdt_remove(struct platform_device *pdev)
        release_mem_region(res->start, resource_size(res));
        platform_set_drvdata(pdev, NULL);

+       if (wdev->irq)
+               free_irq(wdev->irq, wdev);
+
        iounmap(wdev->base);

        kfree(wdev);
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index 09b774c..c9980d3 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -38,7 +38,11 @@
 #define OMAP_WATCHDOG_LDR              (0x2c)
 #define OMAP_WATCHDOG_TGR              (0x30)
 #define OMAP_WATCHDOG_WPS              (0x34)
+#define OMAP_WATCHDOG_WDLY             (0x44)
 #define OMAP_WATCHDOG_SPR              (0x48)
+#define OMAP_WATCHDOG_WIRQSTAT         (0x58)
+#define OMAP_WATCHDOG_WIRQENSET                (0x5c)
+#define OMAP_WATCHDOG_WIRQENCLR                (0x60)

 /* Using the prescaler, the OMAP watchdog could go for many
  * months before firing.  These limits work without scaling,
--


Thanks
Lokesh

+#endif

        wdev->omap_wdt_miscdev.parent = &pdev->dev;
        wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to