Linux Watchdog driver development
 help / color / mirror / Atom feed
From: Guenter Roeck <linux@roeck-us.net>
To: Hui Chun Ong <hui.chun.ong@ni.com>
Cc: "corbet@lwn.net" <corbet@lwn.net>,
	"wim@iguana.be" <wim@iguana.be>,
	"rjw@rjwysocki.net" <rjw@rjwysocki.net>,
	Julia Cartwright <julia.cartwright@ni.com>,
	"mika.westerberg@linux.intel.com"
	<mika.westerberg@linux.intel.com>,
	"linux-watchdog@vger.kernel.org" <linux-watchdog@vger.kernel.org>,
	"linux-doc@vger.kernel.org" <linux-doc@vger.kernel.org>,
	Jonathan Hearn <jonathan.hearn@ni.com>
Subject: Re: [PATCH v3] watchdog: nic7018_wdt: Add NIC7018 watchdog driver
Date: Tue, 13 Dec 2016 09:05:27 -0800	[thread overview]
Message-ID: <20161213170527.GB29124@roeck-us.net> (raw)
In-Reply-To: <1481624182.54688.13.camel@ni.com>

On Tue, Dec 13, 2016 at 10:16:23AM +0000, Hui Chun Ong wrote:
> On Sat, 2016-12-10 at 09:22 -0800, Guenter Roeck wrote:
> > On 12/10/2016 02:25 AM, Hui Chun Ong wrote:
> > > 
> > > Add support for the watchdog timer on PXI Embedded Controller.
> > > 
> > > Signed-off-by: Hui Chun Ong <hui.chun.ong@ni.com>
> > > ---
> > > v2: Remove mutex lock and platform_device *pdev fields from struct
> > > nic7018_wdt.
> > >     Update config NIC7018_WDT description.
> > >     Update nic7018_get_config() to never return error.
> > >     Remove checking for IO resource size in nic7018_probe().
> > > 
> > > v1: Remove non-standard attributes.
> > >     Change from acpi_driver to platform_driver.
> > >     Rename driver from ni7018_wdt to nic7018_wdt.
> > > ---
> > >  Documentation/watchdog/watchdog-parameters.txt |   5 +
> > >  drivers/watchdog/Kconfig                       |  10 +
> > >  drivers/watchdog/Makefile                      |   1 +
> > >  drivers/watchdog/nic7018_wdt.c                 | 277
> > > +++++++++++++++++++++++++
> > >  4 files changed, 293 insertions(+)
> > >  create mode 100644 drivers/watchdog/nic7018_wdt.c
> > > 
> > > diff --git a/Documentation/watchdog/watchdog-parameters.txt
> > > b/Documentation/watchdog/watchdog-parameters.txt
> > > index a8d3642..bd142fa 100644
> > > --- a/Documentation/watchdog/watchdog-parameters.txt
> > > +++ b/Documentation/watchdog/watchdog-parameters.txt
> > > @@ -209,6 +209,11 @@ timeout: Initial watchdog timeout in seconds
> > > (0<timeout<516, default=60)
> > >  nowayout: Watchdog cannot be stopped once started
> > >  	(default=kernel config parameter)
> > >  -------------------------------------------------
> > > +nic7018_wdt:
> > > +timeout: Initial watchdog timeout in seconds (0<timeout<464,
> > > default=80)
> > > +nowayout: Watchdog cannot be stopped once started
> > > +	(default=kernel config parameter)
> > > +-------------------------------------------------
> > >  nuc900_wdt:
> > >  heartbeat: Watchdog heartbeats in seconds.
> > >  	(default = 15)
> > > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> > > index fdd3228..baa79825 100644
> > > --- a/drivers/watchdog/Kconfig
> > > +++ b/drivers/watchdog/Kconfig
> > > @@ -1325,6 +1325,16 @@ config NI903X_WDT
> > >  	  To compile this driver as a module, choose M here: the
> > > module will be
> > >  	  called ni903x_wdt.
> > > 
> > > +config NIC7018_WDT
> > > +	tristate "NIC7018 Watchdog"
> > > +	depends on X86 && ACPI
> > > +	select WATCHDOG_CORE
> > > +	---help---
> > > +	  Support for National Instruments NIC7018 Watchdog.
> > > +
> > > +	  To compile this driver as a module, choose M here: the
> > > module will be
> > > +	  called nic7018_wdt.
> > > +
> > >  # M32R Architecture
> > > 
> > >  # M68K Architecture
> > > diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> > > index caa9f4a..bd88e2e 100644
> > > --- a/drivers/watchdog/Makefile
> > > +++ b/drivers/watchdog/Makefile
> > > @@ -139,6 +139,7 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) +=
> > > intel_scu_watchdog.o
> > >  obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
> > >  obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o
> > >  obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o
> > > +obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o
> > > 
> > >  # M32R Architecture
> > > 
> > > diff --git a/drivers/watchdog/nic7018_wdt.c
> > > b/drivers/watchdog/nic7018_wdt.c
> > > new file mode 100644
> > > index 0000000..9b7b8d3
> > > --- /dev/null
> > > +++ b/drivers/watchdog/nic7018_wdt.c
> > > @@ -0,0 +1,277 @@
> > > +/*
> > > + * Copyright (C) 2016 National Instruments Corp.
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > modify
> > > + * it under the terms of the GNU General Public License as
> > > published by
> > > + * the Free Software Foundation; either version 2 of the License,
> > > or
> > > + * (at your option) any later version.
> > > + *
> > > + * This program is distributed in the hope that it will be useful,
> > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > + * GNU General Public License for more details.
> > > + */
> > > +
> > > +#include <linux/acpi.h>
> > > +#include <linux/bitops.h>
> > > +#include <linux/device.h>
> > > +#include <linux/io.h>
> > > +#include <linux/module.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/watchdog.h>
> > > +
> > > +#define LOCK			0xA5
> > > +#define UNLOCK			0x5A
> > > +
> > > +#define WDT_CTRL_RESET_EN	BIT(7)
> > > +#define WDT_RELOAD_PORT_EN	BIT(7)
> > > +
> > > +#define WDT_CTRL		1
> > > +#define WDT_RELOAD_CTRL		2
> > > +#define WDT_PRESET_PRESCALE	4
> > > +#define WDT_REG_LOCK		5
> > > +#define WDT_COUNT		6
> > > +#define WDT_RELOAD_PORT		7
> > > +
> > > +#define WDT_MIN_TIMEOUT		1
> > > +#define WDT_MAX_TIMEOUT		464
> > > +#define WDT_DEFAULT_TIMEOUT	80
> > > +
> > > +#define WDT_MAX_COUNTER		15
> > > +
> > > +static unsigned int timeout;
> > > +module_param(timeout, uint, 0);
> > > +MODULE_PARM_DESC(timeout,
> > > +		 "Watchdog timeout in seconds. (default="
> > > +		 __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")");
> > > +
> > > +static bool nowayout = WATCHDOG_NOWAYOUT;
> > > +module_param(nowayout, bool, 0);
> > > +MODULE_PARM_DESC(nowayout,
> > > +		 "Watchdog cannot be stopped once started.
> > > (default="
> > > +		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
> > > +
> > > +struct nic7018_wdt {
> > > +	u16 io_base;
> > > +	u32 period_ms;
> > > +	struct watchdog_device wdd;
> > > +};
> > > +
> > > +struct nic7018_config {
> > > +	u32 period_ms;
> > > +	u8 divider;
> > > +};
> > > +
> > > +static const struct nic7018_config nic7018_configs[] = {
> > > +	{   125, 3 },
> > The maximum timeout is (125 * 15) - 62, or 1813 ms. This will never
> > be selected,
> > since with a timeout of 2s count will be 17 below, and the entry will
> > be skipped.
> > With a timeout of 1000, the second table entry will be used as well
> > since the
> > timeout with the first entry is not exactly 1 second.
> > 
> > Given that, you might as well drop this entry.
> > 
> > 
> > > 
> > > +	{  2000, 4 },
> > > +	{ 32000, 5 },
> > > +};
> > > +
> > > +static inline u32 nic7018_timeout_ms(u32 period_ms, u8 counter)
> > > +{
> > > +	return period_ms * counter - period_ms / 2;
> > > +}
> > > +
> > > +static const struct nic7018_config *nic7018_get_config(u32
> > > timeout_ms,
> > > +						       u8
> > > *counter)
> > > +{
> > > +	u32 delta, i, best_delta = U32_MAX;
> > > +	const struct nic7018_config *config, *best_config = NULL;
> > > +	u8 count;
> > > +	*counter = WDT_MAX_COUNTER;
> > > +
> > > +	for (i = 0; i < ARRAY_SIZE(nic7018_configs); i++) {
> > > +		config = &nic7018_configs[i];
> > > +
> > > +		count = DIV_ROUND_UP(timeout_ms + config-
> > > >period_ms / 2,
> > > +				     config->period_ms);
> > > +
> > > +		if (count > WDT_MAX_COUNTER)
> > > +			continue;
> > > +
> > > +		delta = nic7018_timeout_ms(config->period_ms,
> > > count) -
> > > +			timeout_ms;
> > > +
> > > +		if (delta < best_delta) {
> > > +			best_delta = delta;
> > > +			best_config = config;
> > > +			*counter = count;
> > > +		}
> > > +	}
> > > +
> > > +	return (!best_config) ? config : best_config;
> > Unecessary (), and
> > 	return best_config ? : config;
> > works without the '!'.
> > 
> > Also, given the above, it seems to me that
> > 
> > 	if (timeout < 30 && timeout != 16) {
> > 		config = &nic7018_configs[0];
> > 		count = timeout / 2 + 1;
> > 	} else {
> > 		config = &nic7018_configs[1];
> > 		count = DIV_ROUND_UP(timeout + 16, 32);
> > 		if (count > WDT_MAX_COUNTER;
> > 			count = WDT_MAX_COUNTER;
> > 	}
> > 	*counter = count;
> > 	return config;
> > 
> > would accomplish the same as your code and be much less complex and
> > easier
> > to understand. As a side effect, you could keep all timeouts in
> > seconds
> > and would not have to deal with milliseconds at all.
> > 
> 
> Is it possible to keep the miliseconds calculation in the driver even
> though its doesn't seem to be needed? The reason is because the
> watchdog timer has miliseconds timeout resolution that we plan to
> utilize for our specific application. Do you foresee the watchdog core
> adding support for miliseconds timeout?
> 

Not anytime soon. There was some argument about it, but in practice Linux
user space demons have a hard time meeting low-second timeouts. On top of that,
it really would only make sense for low-second or sub-second timeouts, but for
those I don't really see the point because it takes much longer to reboot the
kernel.

In my opinion, it is better to keep the code simple and add complexity later
if/when needed. Writing complex code just in case it may be needed at some
point in the future doesn't make much sense to me.

Guenter
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

      reply	other threads:[~2016-12-13 17:05 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-10 10:25 [PATCH v3] watchdog: nic7018_wdt: Add NIC7018 watchdog driver Hui Chun Ong
2016-12-10 17:22 ` Guenter Roeck
2016-12-13 10:16   ` Hui Chun Ong
2016-12-13 17:05     ` Guenter Roeck [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161213170527.GB29124@roeck-us.net \
    --to=linux@roeck-us.net \
    --cc=corbet@lwn.net \
    --cc=hui.chun.ong@ni.com \
    --cc=jonathan.hearn@ni.com \
    --cc=julia.cartwright@ni.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=mika.westerberg@linux.intel.com \
    --cc=rjw@rjwysocki.net \
    --cc=wim@iguana.be \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox