lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Thu, 8 Aug 2013 08:18:37 +0200
From:	Christophe Leroy <christophe.leroy@....fr>
To:	Wim Van Sebroeck <wim@...ana.be>, <scottwood@...escale.com>
CC:	linux-kernel@...r.kernel.org, linux-watchdog@...r.kernel.org,
	linuxppc-dev@...ts.ozlabs.org
Subject: [PATCH v3] Enhanced support for MPC8xx/8xxx watchdog

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 <christophe.leroy@....fr>

--- 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. (0<timeout<65536, default=65535)");
+	"Watchdog SW timeout in seconds. (0 < timeout < 65536s, default = "
+				__MODULE_STRING(WD_TIMO) "s)");
+static u16 hw_timeout = 0xffff;
+module_param(hw_timeout, ushort, 0);
+MODULE_PARM_DESC(hw_timeout,
+	"Watchdog HW timeout in ticks. (0 < hw_timeout < 65536, "
+		"default = 65535)");
 
 static bool reset = 1;
 module_param(reset, bool, 0);
@@ -72,10 +80,16 @@
  * to 0
  */
 static int prescale = 1;
-static unsigned int timeout_sec;
+static unsigned int hw_timeout_sec;
 
+/*
+ * wdt_auto is set to 1 when watchdog is automatically refreshed by the kernel
+ * (when /dev/watchdog is not open)
+ */
+static bool wdt_auto = 1;
 static unsigned long wdt_is_open;
 static DEFINE_SPINLOCK(wdt_spinlock);
+static unsigned long wdt_last_ping;
 
 static void mpc8xxx_wdt_keepalive(void)
 {
@@ -91,9 +105,20 @@
 
 static void mpc8xxx_wdt_timer_ping(unsigned long arg)
 {
-	mpc8xxx_wdt_keepalive();
-	/* We're pinging it twice faster than needed, just to be sure. */
-	mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
+	if (wdt_auto)
+		wdt_last_ping = jiffies;
+
+	if (jiffies - wdt_last_ping <= timeout * HZ) {
+		mpc8xxx_wdt_keepalive();
+		/* We're pinging it twice faster than needed, to be sure. */
+		mod_timer(&wdt_timer, jiffies + HZ * hw_timeout_sec / 2);
+	}
+}
+
+static void mpc8xxx_wdt_sw_keepalive(void)
+{
+	wdt_last_ping = jiffies;
+	mpc8xxx_wdt_timer_ping(0);
 }
 
 static void mpc8xxx_wdt_pr_warn(const char *msg)
@@ -106,7 +131,7 @@
 				 size_t count, loff_t *ppos)
 {
 	if (count)
-		mpc8xxx_wdt_keepalive();
+		mpc8xxx_wdt_sw_keepalive();
 	return count;
 }
 
@@ -126,11 +151,11 @@
 	if (reset)
 		tmp |= SWCRR_SWRI;
 
-	tmp |= timeout << 16;
+	tmp |= hw_timeout << 16;
 
 	out_be32(&wd_base->swcrr, 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,
 		},
 	},
 	{},
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ