From patchwork Tue Nov 7 16:23:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Leroy X-Patchwork-Id: 835363 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3yWZYm2hzkz9s7G for ; Wed, 8 Nov 2017 03:26:20 +1100 (AEDT) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3yWZYm1rVFzDrL1 for ; Wed, 8 Nov 2017 03:26:20 +1100 (AEDT) X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=c-s.fr (client-ip=93.17.236.30; helo=pegase1.c-s.fr; envelope-from=christophe.leroy@c-s.fr; receiver=) Received: from pegase1.c-s.fr (pegase1.c-s.fr [93.17.236.30]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3yWZW82PVnzDqlM for ; Wed, 8 Nov 2017 03:24:02 +1100 (AEDT) Received: from localhost (mailhub1-int [192.168.12.234]) by localhost (Postfix) with ESMTP id 3yWZVs1D81z9tvrr; Tue, 7 Nov 2017 17:23:49 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at c-s.fr Received: from pegase1.c-s.fr ([192.168.12.234]) by localhost (pegase1.c-s.fr [192.168.12.234]) (amavisd-new, port 10024) with ESMTP id chXrxKLHi3TQ; Tue, 7 Nov 2017 17:23:49 +0100 (CET) Received: from messagerie.si.c-s.fr (messagerie.si.c-s.fr [192.168.25.192]) by pegase1.c-s.fr (Postfix) with ESMTP id 3yWZVr4ZTmz9tvrl; Tue, 7 Nov 2017 17:23:48 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by messagerie.si.c-s.fr (Postfix) with ESMTP id E6FD18B84D; Tue, 7 Nov 2017 17:23:56 +0100 (CET) X-Virus-Scanned: amavisd-new at c-s.fr Received: from messagerie.si.c-s.fr ([127.0.0.1]) by localhost (messagerie.si.c-s.fr [127.0.0.1]) (amavisd-new, port 10023) with ESMTP id IIqLUrIeWDmu; Tue, 7 Nov 2017 17:23:56 +0100 (CET) Received: from po15668-vm-win7.idsi0.si.c-s.fr (po15451.idsi0.si.c-s.fr [172.25.231.3]) by messagerie.si.c-s.fr (Postfix) with ESMTP id A33778B84C; Tue, 7 Nov 2017 17:23:56 +0100 (CET) Received: by po15668-vm-win7.idsi0.si.c-s.fr (Postfix, from userid 0) id 55E106C399; Tue, 7 Nov 2017 17:23:56 +0100 (CET) From: Christophe Leroy Subject: [PATCH] watchdog: mpc8xxx: use the core worker function To: Wim Van Sebroeck , Guenter Roeck Message-Id: <20171107162356.55E106C399@po15668-vm-win7.idsi0.si.c-s.fr> Date: Tue, 7 Nov 2017 17:23:56 +0100 (CET) X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.24 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" The watchdog core includes a worker function which pings the watchdog until user app starts pinging it and which also pings it if the HW require more frequent pings. Use that function instead of the dedicated timer. In the mean time, we can allow the user to change the timeout. Then change the timeout module parameter to use seconds and use the watchdog_init_timeout() core function. On some HW (eg: the 8xx), SWCRR contains bits unrelated to the watchdog which have to be preserved upon write. This driver has nothing preventing the use of the magic close, so enable it. Signed-off-by: Christophe Leroy --- drivers/watchdog/mpc8xxx_wdt.c | 86 ++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 366e5c7e650b..c2ac4b6b1253 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -31,10 +30,13 @@ #include #include +#define WATCHDOG_TIMEOUT 10 + struct mpc8xxx_wdt { __be32 res0; __be32 swcrr; /* System watchdog control register */ #define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */ +#define SWCRR_SWF 0x00000008 /* Software Watchdog Freeze (mpc8xx). */ #define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */ #define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/ #define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */ @@ -52,14 +54,15 @@ struct mpc8xxx_wdt_type { struct mpc8xxx_wdt_ddata { struct mpc8xxx_wdt __iomem *base; struct watchdog_device wdd; - struct timer_list timer; spinlock_t lock; + int prescaler; }; -static u16 timeout = 0xffff; +static u16 timeout; module_param(timeout, ushort, 0); MODULE_PARM_DESC(timeout, - "Watchdog timeout in ticks. (0lock); } -static void mpc8xxx_wdt_timer_ping(unsigned long arg) -{ - struct mpc8xxx_wdt_ddata *ddata = (void *)arg; - - mpc8xxx_wdt_keepalive(ddata); - /* We're pinging it twice faster than needed, just to be sure. */ - mod_timer(&ddata->timer, jiffies + HZ * ddata->wdd.timeout / 2); -} - static int mpc8xxx_wdt_start(struct watchdog_device *w) { struct mpc8xxx_wdt_ddata *ddata = container_of(w, struct mpc8xxx_wdt_ddata, wdd); - - u32 tmp = SWCRR_SWEN | SWCRR_SWPR; + u32 tmp; + u32 timeout; /* Good, fire up the show */ + tmp = in_be32(&ddata->base->swcrr); + tmp &= ~(SWCRR_SWTC | SWCRR_SWF | SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR); + tmp |= SWCRR_SWEN | SWCRR_SWPR; + if (reset) tmp |= SWCRR_SWRI; - tmp |= timeout << 16; + timeout = ddata->wdd.timeout * fsl_get_sys_freq() / ddata->prescaler; + tmp |= min(timeout, 0xffffU) << 16; out_be32(&ddata->base->swcrr, tmp); - del_timer_sync(&ddata->timer); + tmp = in_be32(&ddata->base->swcrr); + if (!(tmp & SWCRR_SWEN)) + return -EOPNOTSUPP; + + ddata->wdd.max_hw_heartbeat_ms = ((tmp >> 16) * ddata->prescaler) / + (fsl_get_sys_freq() / 1000); + ddata->wdd.min_timeout = ddata->wdd.max_hw_heartbeat_ms / 1000; + if (ddata->wdd.timeout < ddata->wdd.min_timeout) + ddata->wdd.timeout = ddata->wdd.min_timeout; return 0; } @@ -118,17 +125,8 @@ static int mpc8xxx_wdt_ping(struct watchdog_device *w) return 0; } -static int mpc8xxx_wdt_stop(struct watchdog_device *w) -{ - struct mpc8xxx_wdt_ddata *ddata = - container_of(w, struct mpc8xxx_wdt_ddata, wdd); - - mod_timer(&ddata->timer, jiffies); - return 0; -} - static struct watchdog_info mpc8xxx_wdt_info = { - .options = WDIOF_KEEPALIVEPING, + .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT, .firmware_version = 1, .identity = "MPC8xxx", }; @@ -137,7 +135,6 @@ static struct watchdog_ops mpc8xxx_wdt_ops = { .owner = THIS_MODULE, .start = mpc8xxx_wdt_start, .ping = mpc8xxx_wdt_ping, - .stop = mpc8xxx_wdt_stop, }; static int mpc8xxx_wdt_probe(struct platform_device *ofdev) @@ -148,7 +145,6 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) struct mpc8xxx_wdt_ddata *ddata; u32 freq = fsl_get_sys_freq(); bool enabled; - unsigned int timeout_sec; wdt_type = of_device_get_match_data(&ofdev->dev); if (!wdt_type) @@ -173,35 +169,34 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) } spin_lock_init(&ddata->lock); - setup_timer(&ddata->timer, mpc8xxx_wdt_timer_ping, - (unsigned long)ddata); ddata->wdd.info = &mpc8xxx_wdt_info, ddata->wdd.ops = &mpc8xxx_wdt_ops, - /* Calculate the timeout in seconds */ - timeout_sec = (timeout * wdt_type->prescaler) / freq; - - ddata->wdd.timeout = timeout_sec; + ddata->wdd.timeout = WATCHDOG_TIMEOUT; + watchdog_init_timeout(&ddata->wdd, timeout, &ofdev->dev); + ddata->prescaler = wdt_type->prescaler; watchdog_set_nowayout(&ddata->wdd, nowayout); + /* + * If the watchdog was previously enabled or we're running on + * MPC8xxx, we should ping the wdt from the kernel until the + * userspace handles it. + */ + if (enabled) { + mpc8xxx_wdt_start(&ddata->wdd); + set_bit(WDOG_HW_RUNNING, &ddata->wdd.status); + } + ret = watchdog_register_device(&ddata->wdd); if (ret) { pr_err("cannot register watchdog device (err=%d)\n", ret); return ret; } - pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n", - reset ? "reset" : "interrupt", timeout, timeout_sec); - - /* - * If the watchdog was previously enabled or we're running on - * MPC8xxx, we should ping the wdt from the kernel until the - * userspace handles it. - */ - if (enabled) - mod_timer(&ddata->timer, jiffies); + pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n", + reset ? "reset" : "interrupt", ddata->wdd.timeout); platform_set_drvdata(ofdev, ddata); return 0; @@ -213,7 +208,6 @@ static int mpc8xxx_wdt_remove(struct platform_device *ofdev) pr_crit("Watchdog removed, expect the %s soon!\n", reset ? "reset" : "machine check exception"); - del_timer_sync(&ddata->timer); watchdog_unregister_device(&ddata->wdd); return 0;