lkml.org 
[lkml]   [2021]   [Apr]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH] watchdog: mtk: support pre-timeout when the bark irq is available
Date
Use the bark interrupt as the pretimeout notifier if available.

By default, the pretimeout notification shall occur one second earlier
than the timeout.

Signed-off-by: Wang Qing <wangqing@vivo.com>
---
drivers/watchdog/mtk_wdt.c | 47 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index 97ca993..8b919cc
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -25,6 +25,7 @@
#include <linux/reset-controller.h>
#include <linux/types.h>
#include <linux/watchdog.h>
+#include <linux/interrupt.h>

#define WDT_MAX_TIMEOUT 31
#define WDT_MIN_TIMEOUT 1
@@ -234,18 +235,35 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
void __iomem *wdt_base = mtk_wdt->wdt_base;
int ret;

- ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+ ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout - wdt_dev->pretimeout);
if (ret < 0)
return ret;

reg = ioread32(wdt_base + WDT_MODE);
reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
+ if (wdt_dev->pretimeout)
+ reg |= WDT_MODE_IRQ_EN;
reg |= (WDT_MODE_EN | WDT_MODE_KEY);
iowrite32(reg, wdt_base + WDT_MODE);

return 0;
}

+static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,
+ unsigned int timeout)
+{
+ wdd->pretimeout = timeout;
+ return mtk_wdt_start(wdd);
+}
+
+static irqreturn_t mtk_wdt_isr(int irq, void *arg)
+{
+ struct watchdog_device *wdd = arg;
+ watchdog_notify_pretimeout(wdd);
+
+ return IRQ_HANDLED;
+}
+
static const struct watchdog_info mtk_wdt_info = {
.identity = DRV_NAME,
.options = WDIOF_SETTIMEOUT |
@@ -253,12 +271,21 @@ static const struct watchdog_info mtk_wdt_info = {
WDIOF_MAGICCLOSE,
};

+static const struct watchdog_info mtk_wdt_pt_info = {
+ .identity = DRV_NAME,
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_PRETIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
static const struct watchdog_ops mtk_wdt_ops = {
.owner = THIS_MODULE,
.start = mtk_wdt_start,
.stop = mtk_wdt_stop,
.ping = mtk_wdt_ping,
.set_timeout = mtk_wdt_set_timeout,
+ .set_pretimeout = mtk_wdt_set_pretimeout,
.restart = mtk_wdt_restart,
};

@@ -267,7 +294,7 @@ static int mtk_wdt_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mtk_wdt_dev *mtk_wdt;
const struct mtk_wdt_data *wdt_data;
- int err;
+ int err,irq;

mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
if (!mtk_wdt)
@@ -279,7 +306,21 @@ static int mtk_wdt_probe(struct platform_device *pdev)
if (IS_ERR(mtk_wdt->wdt_base))
return PTR_ERR(mtk_wdt->wdt_base);

- mtk_wdt->wdt_dev.info = &mtk_wdt_info;
+ irq = platform_get_irq(pdev, 0);
+ if (irq > 0) {
+ err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark", &mtk_wdt->wdt_dev);
+ if (err)
+ return err;
+
+ mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info;
+ mtk_wdt->wdt_dev.pretimeout = 1;
+ } else {
+ if (irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ mtk_wdt->wdt_dev.info = &mtk_wdt_info;
+ }
+
mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000;
--
2.7.4
\
 
 \ /
  Last update: 2021-04-09 12:18    [W:0.043 / U:0.028 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site