All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] watchdog: Add watchdog timer support for the WinSystems EBC-C384
@ 2016-01-22  1:11 William Breathitt Gray
  2016-01-22  3:42 ` Guenter Roeck
  0 siblings, 1 reply; 4+ messages in thread
From: William Breathitt Gray @ 2016-01-22  1:11 UTC (permalink / raw)
  To: wim, linux; +Cc: linux-watchdog, linux-kernel

The WinSystems EBC-C384 has an onboard watchdog timer. The timeout range
supported by the watchdog timer is 1 second to 255 minutes. Timeouts
under 256 seconds have a 1 second resolution, while the rest have a 1
minute resolution.

This driver adds watchdog timer support for this onboard watchdog timer.
The timeout may be configured via the timeout module parameter.

Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
---
 MAINTAINERS                     |   6 ++
 drivers/watchdog/Kconfig        |   9 ++
 drivers/watchdog/Makefile       |   1 +
 drivers/watchdog/ebc-c384_wdt.c | 226 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 242 insertions(+)
 create mode 100644 drivers/watchdog/ebc-c384_wdt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b1e3da7..c058abf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11629,6 +11629,12 @@ M:	David Härdeman <david@hardeman.nu>
 S:	Maintained
 F:	drivers/media/rc/winbond-cir.c
 
+WINSYSTEMS EBC-C384 WATCHDOG DRIVER
+M:	William Breathitt Gray <vilhelm.gray@gmail.com>
+L:	linux-watchdog@vger.kernel.org
+S:	Maintained
+F:	drivers/watchdog/ebc-c384_wdt.c
+
 WIMAX STACK
 M:	Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
 M:	linux-wimax@intel.com
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 4f0e7be..94569ec 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -711,6 +711,15 @@ config ALIM7101_WDT
 
 	  Most people will say N.
 
+config EBC_C386_WDT
+	tristate "WinSystems EBC-C384 watchdog timer support"
+	depends on X86
+	select WATCHDOG_CORE
+	help
+	  Enables watchdog timer support for the watchdog timer on the
+	  WinSystems EBC-C384 motherboard. The timeout may be configured via
+	  the timeout module parameter.
+
 config F71808E_WDT
 	tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
 	depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index f566753..1522316 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
 obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
 obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
 obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
+obj-$(CONFIG_EBC_C386_WDT) += ebc-c384_wdt.o
 obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
 obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o
 obj-$(CONFIG_GEODE_WDT) += geodewdt.o
diff --git a/drivers/watchdog/ebc-c384_wdt.c b/drivers/watchdog/ebc-c384_wdt.c
new file mode 100644
index 0000000..1d7bd67
--- /dev/null
+++ b/drivers/watchdog/ebc-c384_wdt.c
@@ -0,0 +1,226 @@
+/*
+ * Watchdog timer driver for the WinSystems EBC-C384
+ * Copyright (C) 2016 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+#define MODULE_NAME "ebc-c384_wdt"
+#define WATCHDOG_TIMEOUT 60
+
+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) ")");
+
+static unsigned timeout = WATCHDOG_TIMEOUT;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
+	__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+/**
+ * struct ebc_c384_wdt - Watchdog timer device private data structure
+ * @wdd:	instance of struct watchdog_device
+ * @lock:	synchronization lock to prevent race conditions
+ * @base:	base port address of the device
+ * @extent:	extent of port address region of the device
+ */
+struct ebc_c384_wdt {
+	struct watchdog_device wdd;
+	spinlock_t lock;
+	unsigned base;
+	unsigned extent;
+};
+
+static int ebc_c384_wdt_start(struct watchdog_device *wdev)
+{
+	struct ebc_c384_wdt *wdt = watchdog_get_drvdata(wdev);
+
+	return wdt->wdd.ops->set_timeout(wdev, wdt->wdd.timeout);
+}
+
+static int ebc_c384_wdt_stop(struct watchdog_device *wdev)
+{
+	struct ebc_c384_wdt *wdt = watchdog_get_drvdata(wdev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt->lock, flags);
+
+	outb(0x00, wdt->base + 2);
+
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
+}
+
+static int ebc_c384_wdt_set_timeout(struct watchdog_device *wdev, unsigned t)
+{
+	struct ebc_c384_wdt *wdt = watchdog_get_drvdata(wdev);
+	unsigned long flags;
+	unsigned minutes = 0;
+
+	if (!t || t > wdt->wdd.max_timeout)
+		return -EINVAL;
+
+	spin_lock_irqsave(&wdt->lock, flags);
+
+	/* resolution is in minutes for timeouts greater than 255 seconds */
+	if (t > 255) {
+		/* truncate seconds to minute resolution */
+		minutes = t/60;
+
+		/* set watchdog timer for minutes */
+		outb(0x80, wdt->base + 1);
+		outb(minutes, wdt->base + 2);
+
+		wdt->wdd.timeout = minutes * 60;
+	} else {
+		/* set watchdog timer for seconds */
+		outb(0x00, wdt->base + 1);
+		outb(t, wdt->base + 2);
+
+		wdt->wdd.timeout = t;
+	}
+
+	spin_unlock_irqrestore(&wdt->lock, flags);
+
+	return 0;
+}
+
+static const struct watchdog_ops ebc_c384_wdt_ops = {
+	.start = ebc_c384_wdt_start,
+	.stop = ebc_c384_wdt_stop,
+	.set_timeout = ebc_c384_wdt_set_timeout
+};
+
+static const struct watchdog_info ebc_c384_wdt_info = {
+	.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT,
+	.identity = MODULE_NAME
+};
+
+static int __init ebc_c384_wdt_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ebc_c384_wdt *wdt;
+	const unsigned base = 0x564;
+	const unsigned extent = 5;
+	const char *const name = dev_name(dev);
+	int err;
+
+	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+
+	if (!request_region(base, extent, name)) {
+		dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
+			name, base, base + extent);
+		err = -EBUSY;
+		goto err_lock_io_port;
+	}
+
+	dev_set_drvdata(dev, wdt);
+
+	wdt->wdd.info = &ebc_c384_wdt_info;
+	wdt->wdd.ops = &ebc_c384_wdt_ops;
+	wdt->wdd.min_timeout = 1;
+	wdt->wdd.max_timeout = 15300;
+	wdt->base = base;
+	wdt->extent = extent;
+
+	spin_lock_init(&wdt->lock);
+
+	watchdog_set_nowayout(&wdt->wdd, nowayout);
+	watchdog_set_drvdata(&wdt->wdd, wdt);
+
+	err = watchdog_init_timeout(&wdt->wdd, timeout, dev);
+	if (err)
+		goto err_init_timeout;
+
+	err = watchdog_register_device(&wdt->wdd);
+	if (err)
+		goto err_register_wdt;
+
+	return 0;
+
+err_register_wdt:
+err_init_timeout:
+	release_region(base, extent);
+err_lock_io_port:
+	return err;
+}
+
+static int ebc_c384_wdt_remove(struct platform_device *pdev)
+{
+	struct ebc_c384_wdt *wdt = platform_get_drvdata(pdev);
+
+	release_region(wdt->base, wdt->extent);
+
+	return 0;
+}
+
+static struct platform_driver ebc_c384_wdt_driver = {
+	.driver = {
+		.name = MODULE_NAME
+	},
+	.remove = ebc_c384_wdt_remove
+};
+
+static struct platform_device *ebc_c384_wdt_device;
+
+static int __init ebc_c384_wdt_init(void)
+{
+	int err;
+
+	ebc_c384_wdt_device = platform_device_alloc(
+		ebc_c384_wdt_driver.driver.name, -1);
+	if (!ebc_c384_wdt_device)
+		return -ENOMEM;
+
+	err = platform_device_add(ebc_c384_wdt_device);
+	if (err)
+		goto err_platform_device;
+
+	err = platform_driver_probe(&ebc_c384_wdt_driver, ebc_c384_wdt_probe);
+	if (err)
+		goto err_platform_driver;
+
+	return 0;
+
+err_platform_driver:
+	platform_device_del(ebc_c384_wdt_device);
+err_platform_device:
+	platform_device_put(ebc_c384_wdt_device);
+	return err;
+
+	return 0;
+}
+
+static void __exit ebc_c384_wdt_exit(void)
+{
+	platform_device_unregister(ebc_c384_wdt_device);
+	platform_driver_unregister(&ebc_c384_wdt_driver);
+}
+
+module_init(ebc_c384_wdt_init);
+module_exit(ebc_c384_wdt_exit);
+
+MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
+MODULE_DESCRIPTION("WinSystems EBC-C384 watchdog timer driver");
+MODULE_LICENSE("GPL");
-- 
2.4.10

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] watchdog: Add watchdog timer support for the WinSystems EBC-C384
  2016-01-22  1:11 [PATCH] watchdog: Add watchdog timer support for the WinSystems EBC-C384 William Breathitt Gray
@ 2016-01-22  3:42 ` Guenter Roeck
  2016-01-23 15:29   ` William Breathitt Gray
  0 siblings, 1 reply; 4+ messages in thread
From: Guenter Roeck @ 2016-01-22  3:42 UTC (permalink / raw)
  To: William Breathitt Gray, wim; +Cc: linux-watchdog, linux-kernel

On 01/21/2016 05:11 PM, William Breathitt Gray wrote:
> The WinSystems EBC-C384 has an onboard watchdog timer. The timeout range
> supported by the watchdog timer is 1 second to 255 minutes. Timeouts
> under 256 seconds have a 1 second resolution, while the rest have a 1
> minute resolution.
>
> This driver adds watchdog timer support for this onboard watchdog timer.
> The timeout may be configured via the timeout module parameter.
>
> Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
> ---
>   MAINTAINERS                     |   6 ++
>   drivers/watchdog/Kconfig        |   9 ++
>   drivers/watchdog/Makefile       |   1 +
>   drivers/watchdog/ebc-c384_wdt.c | 226 ++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 242 insertions(+)
>   create mode 100644 drivers/watchdog/ebc-c384_wdt.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b1e3da7..c058abf 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11629,6 +11629,12 @@ M:	David Härdeman <david@hardeman.nu>
>   S:	Maintained
>   F:	drivers/media/rc/winbond-cir.c
>
> +WINSYSTEMS EBC-C384 WATCHDOG DRIVER
> +M:	William Breathitt Gray <vilhelm.gray@gmail.com>
> +L:	linux-watchdog@vger.kernel.org
> +S:	Maintained
> +F:	drivers/watchdog/ebc-c384_wdt.c
> +
>   WIMAX STACK
>   M:	Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
>   M:	linux-wimax@intel.com
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 4f0e7be..94569ec 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -711,6 +711,15 @@ config ALIM7101_WDT
>
>   	  Most people will say N.
>
> +config EBC_C386_WDT
> +	tristate "WinSystems EBC-C384 watchdog timer support"
> +	depends on X86
> +	select WATCHDOG_CORE
> +	help
> +	  Enables watchdog timer support for the watchdog timer on the
> +	  WinSystems EBC-C384 motherboard. The timeout may be configured via
> +	  the timeout module parameter.
> +
>   config F71808E_WDT
>   	tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
>   	depends on X86
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index f566753..1522316 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -88,6 +88,7 @@ obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
>   obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
>   obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
>   obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
> +obj-$(CONFIG_EBC_C386_WDT) += ebc-c384_wdt.o
>   obj-$(CONFIG_F71808E_WDT) += f71808e_wdt.o
>   obj-$(CONFIG_SP5100_TCO) += sp5100_tco.o
>   obj-$(CONFIG_GEODE_WDT) += geodewdt.o
> diff --git a/drivers/watchdog/ebc-c384_wdt.c b/drivers/watchdog/ebc-c384_wdt.c
> new file mode 100644
> index 0000000..1d7bd67
> --- /dev/null
> +++ b/drivers/watchdog/ebc-c384_wdt.c
> @@ -0,0 +1,226 @@
> +/*
> + * Watchdog timer driver for the WinSystems EBC-C384
> + * Copyright (C) 2016 William Breathitt Gray
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License, version 2, as
> + * published by the Free Software Foundation.
> + *
> + * 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/device.h>
> +#include <linux/errno.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <linux/watchdog.h>
> +
> +#define MODULE_NAME "ebc-c384_wdt"
> +#define WATCHDOG_TIMEOUT 60
> +
> +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) ")");
> +
> +static unsigned timeout = WATCHDOG_TIMEOUT;
> +module_param(timeout, uint, 0);
> +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
> +	__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
> +
> +/**
> + * struct ebc_c384_wdt - Watchdog timer device private data structure
> + * @wdd:	instance of struct watchdog_device
> + * @lock:	synchronization lock to prevent race conditions
> + * @base:	base port address of the device
> + * @extent:	extent of port address region of the device
> + */
> +struct ebc_c384_wdt {
> +	struct watchdog_device wdd;
> +	spinlock_t lock;
> +	unsigned base;
> +	unsigned extent;
> +};
> +
> +static int ebc_c384_wdt_start(struct watchdog_device *wdev)
> +{
> +	struct ebc_c384_wdt *wdt = watchdog_get_drvdata(wdev);
> +
> +	return wdt->wdd.ops->set_timeout(wdev, wdt->wdd.timeout);

This implies that setting the timeout would start the watchdog,
which is inappropriate (the timeout can be set while the watchdog
is stopped).

Also, setting the timeout sets both the resolution _and_ the timeout,
which is probably unnecessary when starting or pinging the watchdog.

> +}
> +
> +static int ebc_c384_wdt_stop(struct watchdog_device *wdev)
> +{
> +	struct ebc_c384_wdt *wdt = watchdog_get_drvdata(wdev);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&wdt->lock, flags);
> +
> +	outb(0x00, wdt->base + 2);
> +
> +	spin_unlock_irqrestore(&wdt->lock, flags);
> +
Is there a reason to believe that the locking provided by the watchdog core
is insufficient ?

> +	return 0;
> +}
> +
> +static int ebc_c384_wdt_set_timeout(struct watchdog_device *wdev, unsigned t)
> +{
> +	struct ebc_c384_wdt *wdt = watchdog_get_drvdata(wdev);
> +	unsigned long flags;
> +	unsigned minutes = 0;

Unnecessary initialization.

> +
> +	if (!t || t > wdt->wdd.max_timeout)
> +		return -EINVAL;

This won't happen.

> +
> +	spin_lock_irqsave(&wdt->lock, flags);
> +
> +	/* resolution is in minutes for timeouts greater than 255 seconds */
> +	if (t > 255) {
> +		/* truncate seconds to minute resolution */
> +		minutes = t/60;

	t / 60;

> +
> +		/* set watchdog timer for minutes */
> +		outb(0x80, wdt->base + 1);
> +		outb(minutes, wdt->base + 2);
> +
> +		wdt->wdd.timeout = minutes * 60;
> +	} else {
> +		/* set watchdog timer for seconds */
> +		outb(0x00, wdt->base + 1);
> +		outb(t, wdt->base + 2);
> +
It may be better to set the number of seconds first before setting the scale.

> +		wdt->wdd.timeout = t;
> +	}
> +
> +	spin_unlock_irqrestore(&wdt->lock, flags);
> +
> +	return 0;
> +}
> +
> +static const struct watchdog_ops ebc_c384_wdt_ops = {
> +	.start = ebc_c384_wdt_start,
> +	.stop = ebc_c384_wdt_stop,
> +	.set_timeout = ebc_c384_wdt_set_timeout
> +};
> +
> +static const struct watchdog_info ebc_c384_wdt_info = {
> +	.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT,
> +	.identity = MODULE_NAME
> +};
> +
> +static int __init ebc_c384_wdt_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct ebc_c384_wdt *wdt;
> +	const unsigned base = 0x564;
> +	const unsigned extent = 5;
> +	const char *const name = dev_name(dev);

What is the value of those const variables ? Why not just use dev_name() and defines ?

> +	int err;
> +

Is there a means to detect if this is the correct system ? DMI, maybe ?
Blindly instantiating the driver seems to be a bit risky and should be avoided
if possible.

> +	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
> +	if (!wdt)
> +		return -ENOMEM;
> +
> +	if (!request_region(base, extent, name)) {

Please use devm_request_region(), or explain why it is not feasible.

> +		dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
> +			name, base, base + extent);

name is redundant and already provided by dev_err().

> +		err = -EBUSY;
> +		goto err_lock_io_port;

		return -EBUSY;

> +	}
> +
> +	dev_set_drvdata(dev, wdt);
> +
> +	wdt->wdd.info = &ebc_c384_wdt_info;
> +	wdt->wdd.ops = &ebc_c384_wdt_ops;
> +	wdt->wdd.min_timeout = 1;
> +	wdt->wdd.max_timeout = 15300;
> +	wdt->base = base;
> +	wdt->extent = extent;

Both base and extent are constants. Why keep them in the data structure ?

> +
> +	spin_lock_init(&wdt->lock);
> +
> +	watchdog_set_nowayout(&wdt->wdd, nowayout);
> +	watchdog_set_drvdata(&wdt->wdd, wdt);
> +
> +	err = watchdog_init_timeout(&wdt->wdd, timeout, dev);
> +	if (err)
> +		goto err_init_timeout;

A more tolerant implementation would set the default timeout.

> +
> +	err = watchdog_register_device(&wdt->wdd);
> +	if (err)
> +		goto err_register_wdt;
> +
> +	return 0;
> +
> +err_register_wdt:
> +err_init_timeout:

Two labels pointing to the same location is unnecessary.

> +	release_region(base, extent);
> +err_lock_io_port:

Unnecessary label. When you use devm_request_region(),
the error handling should no longer be needed at all.

> +	return err;
> +}
> +
> +static int ebc_c384_wdt_remove(struct platform_device *pdev)
> +{
> +	struct ebc_c384_wdt *wdt = platform_get_drvdata(pdev);
> +
> +	release_region(wdt->base, wdt->extent);

No watchdog_unregister_device() ?

> +
> +	return 0;
> +}
> +
> +static struct platform_driver ebc_c384_wdt_driver = {
> +	.driver = {
> +		.name = MODULE_NAME
> +	},
> +	.remove = ebc_c384_wdt_remove
> +};
> +
> +static struct platform_device *ebc_c384_wdt_device;
> +
> +static int __init ebc_c384_wdt_init(void)
> +{
> +	int err;
> +
> +	ebc_c384_wdt_device = platform_device_alloc(
> +		ebc_c384_wdt_driver.driver.name, -1);
> +	if (!ebc_c384_wdt_device)
> +		return -ENOMEM;
> +
> +	err = platform_device_add(ebc_c384_wdt_device);
> +	if (err)
> +		goto err_platform_device;
> +
> +	err = platform_driver_probe(&ebc_c384_wdt_driver, ebc_c384_wdt_probe);
> +	if (err)
> +		goto err_platform_driver;
> +
> +	return 0;
> +
> +err_platform_driver:
> +	platform_device_del(ebc_c384_wdt_device);
> +err_platform_device:
> +	platform_device_put(ebc_c384_wdt_device);
> +	return err;
> +
> +	return 0;
> +}
> +
> +static void __exit ebc_c384_wdt_exit(void)
> +{
> +	platform_device_unregister(ebc_c384_wdt_device);
> +	platform_driver_unregister(&ebc_c384_wdt_driver);
> +}
> +
> +module_init(ebc_c384_wdt_init);
> +module_exit(ebc_c384_wdt_exit);
> +

Have you considered using module_platform_driver_probe() ?

> +MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
> +MODULE_DESCRIPTION("WinSystems EBC-C384 watchdog timer driver");
> +MODULE_LICENSE("GPL");

GPL v2 as stated above.

>
No MODULE_ALIAS ?

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] watchdog: Add watchdog timer support for the WinSystems EBC-C384
  2016-01-22  3:42 ` Guenter Roeck
@ 2016-01-23 15:29   ` William Breathitt Gray
  2016-01-23 20:01     ` Guenter Roeck
  0 siblings, 1 reply; 4+ messages in thread
From: William Breathitt Gray @ 2016-01-23 15:29 UTC (permalink / raw)
  To: Guenter Roeck, wim; +Cc: linux-watchdog, linux-kernel

On 01/21/2016 10:42 PM, Guenter Roeck wrote:
> This implies that setting the timeout would start the watchdog,
> which is inappropriate (the timeout can be set while the watchdog
> is stopped).
> 
> Also, setting the timeout sets both the resolution _and_ the timeout,
> which is probably unnecessary when starting or pinging the watchdog.

Help me understand the functionality of the watchdog operations briefly  
since I'm relatively new to the interface. Is it proper to say that the  
start callback starts (and in my case also pings) the watchdog based on  
the value of the previously configured timeout member, while the         
set_timeout callback merely sets the timeout member itself to the        
correct value in seconds accordingly to the watchdog timer's resolution?

>> +    const unsigned base = 0x564;
>> +    const unsigned extent = 5;
>> +    const char *const name = dev_name(dev);
> 
> What is the value of those const variables ? Why not just use dev_name() and defines ?
> 
>> +    int err;
>> +
> 
> Is there a means to detect if this is the correct system ? DMI, maybe ?
> Blindly instantiating the driver seems to be a bit risky and should be avoided
> if possible.

Unfortunately, the watchdog timer hardware lacks probing capabilities;    
the documentation for the motherboard indicates that the watchdog timer  
is exposed over an ISA-style I/O-mapped port address. In other words,    
the watchdog timer is non-hotpluggable.                                  
                                                                         
I agree that carrying around the constant values in the private data     
structure is somewhat unnecessary, so I'll give them global scope over   
the file. I'm hesitant to lose the type-safety of C variables; is there  
a reason to prefer preprocessor defines over const-qualified variables?

>> +    err = watchdog_init_timeout(&wdt->wdd, timeout, dev);
>> +    if (err)
>> +        goto err_init_timeout;
> 
> A more tolerant implementation would set the default timeout.

Should I remove the timeout module parameter entirely, and simply        
initialize the watchdog_device timeout member to the default timeout I   
want (e.g. wdt->wdd.timeout = 60)? Would I still need to call            
watchdog_init_timeout in that case?

> Have you considered using module_platform_driver_probe() ?

For some reason, I was under the impression that I must allocate a       
platform_device before calling platform_driver_probe. I'll try           
module_platform_driver_probe since that would indeed be far simpler if   
the platform_device setup code is unnecessary.

> No MODULE_ALIAS ?

Since the watchdog timer hardware is non-hotpluggable, I'm not sure I    
should add a MODULE_ALIAS for autoloading the module.

William Breathitt Gray

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] watchdog: Add watchdog timer support for the WinSystems EBC-C384
  2016-01-23 15:29   ` William Breathitt Gray
@ 2016-01-23 20:01     ` Guenter Roeck
  0 siblings, 0 replies; 4+ messages in thread
From: Guenter Roeck @ 2016-01-23 20:01 UTC (permalink / raw)
  To: William Breathitt Gray, wim; +Cc: linux-watchdog, linux-kernel

On 01/23/2016 07:29 AM, William Breathitt Gray wrote:
> On 01/21/2016 10:42 PM, Guenter Roeck wrote:
>> This implies that setting the timeout would start the watchdog,
>> which is inappropriate (the timeout can be set while the watchdog
>> is stopped).
>>
>> Also, setting the timeout sets both the resolution _and_ the timeout,
>> which is probably unnecessary when starting or pinging the watchdog.
>
> Help me understand the functionality of the watchdog operations briefly
> since I'm relatively new to the interface. Is it proper to say that the
> start callback starts (and in my case also pings) the watchdog based on
> the value of the previously configured timeout member, while the
> set_timeout callback merely sets the timeout member itself to the
> correct value in seconds accordingly to the watchdog timer's resolution?
>
Correct. In your case it may be sufficient to just set the 'timeout' variable
to a valid timeout (ie one supported by the hardware).

>>> +    const unsigned base = 0x564;
>>> +    const unsigned extent = 5;
>>> +    const char *const name = dev_name(dev);
>>
>> What is the value of those const variables ? Why not just use dev_name() and defines ?
>>
>>> +    int err;
>>> +
>>
>> Is there a means to detect if this is the correct system ? DMI, maybe ?
>> Blindly instantiating the driver seems to be a bit risky and should be avoided
>> if possible.
>
> Unfortunately, the watchdog timer hardware lacks probing capabilities;
> the documentation for the motherboard indicates that the watchdog timer
> is exposed over an ISA-style I/O-mapped port address. In other words,
> the watchdog timer is non-hotpluggable.
>
So how about DMI ? This is a PC, after all, so it should be possible
to identify the hardware with DMI. We should have _something_ available
to identify the hardware.

> I agree that carrying around the constant values in the private data
> structure is somewhat unnecessary, so I'll give them global scope over
> the file. I'm hesitant to lose the type-safety of C variables; is there
> a reason to prefer preprocessor defines over const-qualified variables?
>
It is the common and established approach to use defines (you use a define
for WATCHDOG_TIMEOUT as well). The type-safety argument doesn't really apply;
to me it is similar to the argument for Yoda programming. The compiler
will happily complain if you use an integer define as pointer, or a string
as integer.

Defines are used all over the kernel, and work perfectly fine. I don't see
a need to change that. Worse, it makes life more difficult for reviewers.

>>> +    err = watchdog_init_timeout(&wdt->wdd, timeout, dev);
>>> +    if (err)
>>> +        goto err_init_timeout;
>>
>> A more tolerant implementation would set the default timeout.
>
> Should I remove the timeout module parameter entirely, and simply
> initialize the watchdog_device timeout member to the default timeout I
> want (e.g. wdt->wdd.timeout = 60)? Would I still need to call
> watchdog_init_timeout in that case?
>
I didn't want to suggest that. One option would be to set
wdt->wdd.timeout = 60 and ignore the return value from watchdog_init_timeout,
like most watchdog drivers. Another would be something like

	wdt->wdd.timeout = WATCHDOG_TIMEOUT;
	if (watchdog_init_timeout(&wdt->wdd, timeout, dev))
		dev_warn(dev, "Invalid timeout %d, using default\n", timeout);

You can also abort, as you currently do, I just think it is a bit strict.

>> Have you considered using module_platform_driver_probe() ?
>
> For some reason, I was under the impression that I must allocate a
> platform_device before calling platform_driver_probe. I'll try
> module_platform_driver_probe since that would indeed be far simpler if
> the platform_device setup code is unnecessary.
>
Ah yes, my mistake. The idea is that another driver (usually a platform
driver, or architecture initialization code) would instantiate the device.
Sorry for the noise.

>> No MODULE_ALIAS ?
>
> Since the watchdog timer hardware is non-hotpluggable, I'm not sure I
> should add a MODULE_ALIAS for autoloading the module.
>
Not sure I understand what that has to do with hotplug. Almost all
of the 39 watchdog drivers defining MODULE_ALIAS are not hot-pluggable.
Ok, let's see if it comes back to bite us ;-).

Guenter

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2016-01-23 20:01 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-22  1:11 [PATCH] watchdog: Add watchdog timer support for the WinSystems EBC-C384 William Breathitt Gray
2016-01-22  3:42 ` Guenter Roeck
2016-01-23 15:29   ` William Breathitt Gray
2016-01-23 20:01     ` Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.