From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933743Ab3HHGSm (ORCPT ); Thu, 8 Aug 2013 02:18:42 -0400 Received: from pegase1.c-s.fr ([93.17.236.30]:58104 "EHLO mailhub1.si.c-s.fr" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932632Ab3HHGSk (ORCPT ); Thu, 8 Aug 2013 02:18:40 -0400 X-Greylist: delayed 1658 seconds by postgrey-1.27 at vger.kernel.org; Thu, 08 Aug 2013 02:18:40 EDT Date: Thu, 8 Aug 2013 08:18:37 +0200 Message-Id: <201308080618.r786IbPg010818@localhost.localdomain> From: Christophe Leroy To: Wim Van Sebroeck , CC: linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Subject: [PATCH v3] Enhanced support for MPC8xx/8xxx watchdog Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch modifies the behaviour of the MPC8xx/8xxx watchdog. On the MPC8xx, at 133Mhz, the maximum timeout of the watchdog timer is 1s, which means it must be pinged twice a second. This is not in line with the Linux watchdog concept which is based on a default watchdog timeout around 60s. This patch introduces an intermediate layer between the CPU and the userspace. The kernel pings the watchdog at the required frequency at the condition that userspace tools refresh it regularly. Existing parameter 'timeout' is renamed 'hw_timeout'. The new parameter 'timeout' allows to set up the userspace timeout. This patch also adds the WDIOC_SETTIMEOUT ioctl to the driver. Signed-off-by: Christophe Leroy --- linux-3.8.13/drivers/watchdog/mpc8xxx_wdt.c 2013-05-11 22:57:46.000000000 +0200 +++ linux/drivers/watchdog/mpc8xxx_wdt.c 2013-08-08 02:12:15.000000000 +0200 @@ -52,10 +52,18 @@ static struct mpc8xxx_wdt __iomem *wd_base; static int mpc8xxx_wdt_init_late(void); -static u16 timeout = 0xffff; -module_param(timeout, ushort, 0); +#define WD_TIMO 60 /* Default timeout = 60 seconds */ + +static uint timeout = WD_TIMO; +module_param(timeout, uint, 0); MODULE_PARM_DESC(timeout, - "Watchdog timeout in ticks. (0swcrr, tmp); - del_timer_sync(&wdt_timer); + wdt_auto = 0; return nonseekable_open(inode, file); } @@ -138,7 +163,8 @@ static int mpc8xxx_wdt_release(struct inode *inode, struct file *file) { if (!nowayout) - mpc8xxx_wdt_timer_ping(0); + wdt_auto = 1; + else mpc8xxx_wdt_pr_warn("watchdog closed"); clear_bit(0, &wdt_is_open); @@ -155,6 +181,7 @@ .firmware_version = 1, .identity = "MPC8xxx", }; + int r; switch (cmd) { case WDIOC_GETSUPPORT: @@ -163,10 +190,15 @@ case WDIOC_GETBOOTSTATUS: return put_user(0, p); case WDIOC_KEEPALIVE: - mpc8xxx_wdt_keepalive(); + mpc8xxx_wdt_sw_keepalive(); return 0; case WDIOC_GETTIMEOUT: - return put_user(timeout_sec, p); + return put_user(timeout, p); + case WDIOC_SETTIMEOUT: + r = get_user(timeout, p); + if (timeout > UINT_MAX / HZ) + timeout = UINT_MAX / HZ; + return r; default: return -ENOTTY; } @@ -215,21 +247,26 @@ ret = -ENOSYS; goto err_unmap; } + if (enabled) + hw_timeout = in_be32(&wd_base->swcrr) >> 16; /* Calculate the timeout in seconds */ if (prescale) - timeout_sec = (timeout * wdt_type->prescaler) / freq; + hw_timeout_sec = (hw_timeout * wdt_type->prescaler) / freq; else - timeout_sec = timeout / freq; + hw_timeout_sec = hw_timeout / freq; + /* Make sure the timeout is not too big */ + if (timeout > UINT_MAX / HZ) + timeout = UINT_MAX / HZ; #ifdef MODULE ret = mpc8xxx_wdt_init_late(); if (ret) goto err_unmap; #endif - pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n", - reset ? "reset" : "interrupt", timeout, timeout_sec); + pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout = %d (%d seconds)\n", + reset ? "reset" : "interrupt", hw_timeout, hw_timeout_sec); /* * If the watchdog was previously enabled or we're running on @@ -273,6 +310,7 @@ .compatible = "fsl,mpc823-wdt", .data = &(struct mpc8xxx_wdt_type) { .prescaler = 0x800, + .hw_enabled = true, }, }, {},