2010-01-18 21:20:43

by Allyn, Mark A

[permalink] [raw]
Subject: [PATCH] Add Linux Driver for Intel Langwell Watchdog

This patch adds a Linux device driver for the Intel Langwell
Watchdog device found on the Intel Mobile Internet device.

The purpose of the watchdog driver is to force a system reboot
in the event that a critical system process either terminates or
gets currupted so that it cannot perform its required duties.

This patch is referenced off the linux-next repository as pulled
on Sunday, January 17, 2010

Signed-off-by: Mark Allyn <[email protected]>

Date: January 17, 2010
---
drivers/watchdog/Kconfig | 7 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/langwell_watchdog.c | 551 ++++++++++++++++++++++++++++++++++
drivers/watchdog/langwell_watchdog.h | 60 ++++
4 files changed, 619 insertions(+), 0 deletions(-)
create mode 100644 drivers/watchdog/langwell_watchdog.c
create mode 100644 drivers/watchdog/langwell_watchdog.h

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 088f32f..4902157 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -448,6 +448,13 @@ config IBMASR
To compile this driver as a module, choose M here: the
module will be called ibmasr.

+config LANGWELL_WATCHDOG
+ tristate "Intel Langwell Watchdog for Mobil Platforms"
+ depends on WATCHDOG
+ help
+ This driver is for the Intel Mobile Platform. If
+ in doubt, set it to N.
+
config WAFER_WDT
tristate "ICP Single Board Computer Watchdog Timer"
depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 475c611..67f936f 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
+obj-$(CONFIG_LANGWELL_WATCHDOG) += langwell_watchdog.o

# M32R Architecture

diff --git a/drivers/watchdog/langwell_watchdog.c b/drivers/watchdog/langwell_watchdog.c
new file mode 100644
index 0000000..050b036
--- /dev/null
+++ b/drivers/watchdog/langwell_watchdog.c
@@ -0,0 +1,551 @@
+/*
+ * Langwell 0.2: An Intel Langwell IOH Based Watchdog Device
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General
+ * Public License 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.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ *
+ */
+
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sfi.h>
+#include <linux/types.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+/* See arch/x86/kernel/ipc_mrst.c */
+#include <asm/ipc_defs.h>
+#include <linux/sftbl.h>
+/* #include <asm/mrst.h> */
+
+#include "langwell_watchdog.h"
+
+
+static DECLARE_WAIT_QUEUE_HEAD(read_wq);
+
+static int flag;
+static int timer_margin = DEFAULT_SOFT_TO_HARD_MARGIN;
+module_param(timer_margin, int, 0);
+
+MODULE_PARM_DESC(timer_margin,
+ "Watchdog timer margin"
+ "Time between interrupt and resetting the system"
+ "The range is from 1 to 160"
+ "This is the time for all keep alives to arrive");
+
+static int timer_set = DEFAULT_TIME;
+module_param(timer_set, int, 0);
+
+MODULE_PARM_DESC(timer_set,
+ "Default Watchdog timer setting"
+ "Complete cycle time"
+ "The range is from 1 to 170"
+ "This is the time for all keep alives to arrive");
+
+/* driver will force boot on closure of device file */
+static int force_boot = 1;
+
+module_param(force_boot, int, 0);
+MODULE_PARM_DESC(force_boot,
+ "A value of 1 means that the driver will reboot"
+ "the system if the /dev/watchdog device is closed"
+ );
+
+/* there is only one device in the system now; this can be made into
+ * an array in the future if we have more than one device */
+
+static struct langwell_watchdog_dev watchdog_device;
+
+/* This is used to force reboot if anyone tries to close this device */
+static void watchdog_fire(void)
+{
+ module_put(THIS_MODULE);
+
+ if (force_boot) {
+ printk(KERN_CRIT PFX "Initiating system reboot.\n");
+ emergency_restart();
+ printk(KERN_CRIT PFX "Reboot didn't ?????\n");
+ }
+
+ else {
+ printk(KERN_CRIT PFX "Reboot would have happend\n");
+ printk(KERN_CRIT PFX "You now have force_boot set to 0\n");
+ printk(KERN_CRIT PFX "I am not rebooting\n");
+ }
+}
+
+/*
+ * Langwell operations
+ */
+
+/* timer interrupt handler */
+irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
+{
+ int int_status;
+ int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
+
+ pr_debug("Watchdog timer - irq 7 interrupt received\n");
+
+ if (int_status != 0)
+ return IRQ_NONE;
+
+ /* is the driver open; if not, then this is spurious */
+ if (watchdog_device.timer_started == 0)
+ return IRQ_HANDLED;
+
+ pr_debug("Watchdog timer - watchdog interrupt received\n");
+
+ /* wake up read to send data to user (reminder for keep alive */
+ flag = 1;
+
+ wake_up_interruptible(&read_wq);
+
+ pr_debug("Watchdog timer - interrupt wakes up read_wq\n");
+
+ return IRQ_HANDLED;
+}
+
+static int langwell_keepalive(void)
+{
+
+ pr_debug("Watchdog timer - langwell keep alive \n");
+ /* read eoi register - clears interrupt */
+ ioread32(watchdog_device.timer_clear_interrupt_addr);
+
+ return 0;
+}
+
+static int langwell_stop(void)
+{
+ pr_debug("Watchdog timer - langwell stop\n");
+
+ iowrite32(0, watchdog_device.timer_control_addr);
+ return 0;
+}
+
+static int langwell_set_heartbeat(u32 t)
+{
+ struct watchdog_reg_data reg_data;
+
+ watchdog_device.timer_set = t;
+ watchdog_device.threshold =
+ timer_margin * watchdog_device.mtmr_ptr->freq;
+ watchdog_device.soft_threshold =
+ (watchdog_device.timer_set - timer_margin)
+ * watchdog_device.mtmr_ptr->freq;
+
+ pr_debug("Watchdog timer - timer_margin is %x (hex) seconds\n",
+ timer_margin);
+
+ pr_debug("Watchdog timer - following are in clock cycles\n");
+
+ pr_debug("Watchdog timer - there are %x (hex) clock cycles\n",
+ watchdog_device.mtmr_ptr->freq);
+
+ pr_debug("Watchdog timer - per second\n");
+
+ pr_debug("Watchdog timer - thres is %x (hex) and warm is %x (hex)\n",
+ watchdog_device.threshold, watchdog_device.soft_threshold);
+
+ pr_debug("Watchdog timer - setting timer_set is %x (hex) seconds\n",
+ watchdog_device.timer_set);
+
+ /* temporarily disable the timer */
+ iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+ /* send the threshold and soft_threshold via IPC to the Lincroft */
+ reg_data.payload1 = watchdog_device.soft_threshold;
+ reg_data.payload2 = watchdog_device.threshold;
+ ipc_set_watchdog(&reg_data);
+
+ pr_debug("Watchdog timer - setting timer to %x (hex)\n",
+ watchdog_device.soft_threshold);
+
+ /* set the timer to the soft threshold */
+ iowrite32(watchdog_device.soft_threshold,
+ watchdog_device.timer_load_count_addr);
+
+ /* read the timer to verify that it has been set */
+ pr_debug("Watchdog timer - watchdog - timer value is %x (hex)\n",
+ ioread32(watchdog_device.timer_current_value_addr));
+
+ /* allow the timer to run */
+ iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+ watchdog_device.timer_started = 1;
+
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+static int langwell_open(struct inode *inode, struct file *file)
+{
+ /* Miscdevice structure pointer already saved in private_data */
+
+ struct watchdog_reg_data reg_data;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (test_and_set_bit(0, &watchdog_device.driver_open))
+ return -ENOTTY;
+
+ /* make sure that the timer set value is within boundaries */
+ if ((timer_set < MIN_TIME_CYCLE) ||
+ (timer_set > MAX_TIME - MIN_TIME_CYCLE)) {
+ pr_debug("Watchdog timer - timer open; timer value %x (hex)"
+ "is out of range from %x to %x (hex)\n",
+ timer_set, MIN_TIME_CYCLE, MAX_TIME - MIN_TIME_CYCLE);
+ return -EINVAL;
+ }
+
+ /* make sure that the timer margin value is within boundaries */
+ if ((timer_margin < MIN_TIME_CYCLE) ||
+ (timer_margin > MAX_TIME - timer_set)) {
+ pr_debug("Watchdog timer - timer open; "
+ "timer margin value %x is out of range from %x to %x (hex)\n",
+ timer_margin, MIN_TIME_CYCLE, MAX_TIME - timer_set);
+ return -EINVAL;
+ }
+
+ /* now set the watchpoints (using the IPC) */
+
+ watchdog_device.timer_set = timer_set;
+ watchdog_device.threshold =
+ timer_margin * watchdog_device.mtmr_ptr->freq;
+ watchdog_device.soft_threshold =
+ (watchdog_device.timer_set - timer_margin)
+ * watchdog_device.mtmr_ptr->freq;
+
+ pr_debug("Watchdog timer - threshold is %x and soft to %x (hex)\n",
+ watchdog_device.threshold, watchdog_device.soft_threshold);
+
+ pr_debug("Watchdog timer - setting heartbeat timer_set is %x (hex)\n",
+ watchdog_device.timer_set);
+
+ /* temporarily disable the timer */
+ iowrite32(0x00000002, watchdog_device.timer_control_addr);
+
+ /* send the threshold and soft_threshold via IPC to the Lincroft */
+ reg_data.payload1 = watchdog_device.soft_threshold;
+ reg_data.payload2 = watchdog_device.threshold;
+ ipc_set_watchdog(&reg_data);
+
+ pr_debug("Watchdog timer - setting timer to %x (hex)\n",
+ watchdog_device.soft_threshold);
+
+ /* set the timer to the soft threshold */
+ iowrite32(watchdog_device.soft_threshold,
+ watchdog_device.timer_load_count_addr);
+
+ /* read the timer to verify that it has been set */
+ pr_debug("Watchdog timer - watchdog - timer value is %x (hex)\n",
+ ioread32(watchdog_device.timer_current_value_addr));
+
+ /* allow the timer to run */
+ iowrite32(0x00000003, watchdog_device.timer_control_addr);
+
+ watchdog_device.timer_started = 1;
+
+ return nonseekable_open(inode, file);
+}
+
+static int langwell_release(struct inode *inode, struct file *file)
+{
+ /*
+ * This watchdog may not be closed! Reboot immediately.
+ */
+ printk(KERN_CRIT PFX
+ "Unexpected close, firing off the watchdog!\n");
+
+ clear_bit(0, &watchdog_device.driver_open);
+
+ /* Reboot system (if force_boot is set) */
+ watchdog_fire();
+
+ /* We should never reach this point. */
+ return 0;
+}
+
+static ssize_t langwell_write(struct file *file,
+ char const *data,
+ size_t len,
+ loff_t *ppos)
+{
+ pr_debug("Langwell Watchdog - write; calling keepalive\n");
+
+ langwell_keepalive();
+
+ return len;
+}
+
+static ssize_t langwell_read(struct file *file,
+ char __user *user_data,
+ size_t len,
+ loff_t *user_ppos)
+{
+ int result;
+ u8 buf = 0;
+
+ pr_debug("Langwell Watchdog - read function called;"
+ " wait for interrupt\n");
+
+ /* we wait for the next interrupt; if more than one */
+ /* interrupt has occurered since the last read, we */
+ /* dont care. The data is not critical. We will do */
+ /* a copy to user each time we get and interrupt */
+ /* It is up to the Watchdog daemon to be ready to */
+ /* do the read (shich signifies that the driver is */
+ /* awaiting a keep alive and that a limited time */
+ /* is available for the keep alive before the system */
+ /* is rebooted by the timer */
+ wait_event_interruptible(read_wq, flag != 0);
+ flag = 0;
+
+ pr_debug("Langwell Watchdog read - interrupt received\n");
+
+ /* Please note that the content of the data is irrelevent */
+ /* All that matters is that the read is available to the user */
+ result = copy_to_user(user_data, (void *)&buf, 1);
+
+ if (result != 0)
+ return -EFAULT;
+ else
+ return 1;
+
+}
+
+static long langwell_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ u32 __user *p = argp;
+ u32 new_margin;
+
+ static const struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT
+ | WDIOF_KEEPALIVEPING,
+ .firmware_version = 0, /* @todo Get from SCU via
+ ipc_get_scu_fw_version()? */
+ .identity = "Langwell IOH Watchdog" /* len < 32 */
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp,
+ &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ pr_debug("Watchdog timer - watchdog - timer current value is %x\n",
+ ioread32(watchdog_device.timer_current_value_addr));
+ return put_user(0, p);
+ case WDIOC_KEEPALIVE:
+ langwell_keepalive();
+
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, p))
+ return -EFAULT;
+
+ if ((new_margin < 0) || (new_margin > MAX_TIME)) {
+ pr_debug("Watchdog timer - value out of range\n"
+ "Value submitted is %d is out of range of %d"
+ " and %d\n", new_margin, MIN_TIME_CYCLE, MAX_TIME);
+ return -EINVAL;
+ }
+
+ pr_debug("Langwell Watchdog - set time out timer is %d\n",
+ new_margin);
+ if (langwell_set_heartbeat(new_margin))
+ return -EINVAL;
+ return 0;
+ case WDIOC_GETTIMEOUT:
+ return put_user(watchdog_device.soft_threshold, p);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+/*
+ * Notifier for system down
+ */
+static int langwell_notify_sys(struct notifier_block *this,
+ unsigned long code,
+ void *another_unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ /* Turn off the watchdog timer. */
+ langwell_stop();
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+static const struct file_operations langwell_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = langwell_write,
+ .read = langwell_read,
+ .unlocked_ioctl = langwell_ioctl,
+ .open = langwell_open,
+ .release = langwell_release,
+};
+
+static int __init watchdog_init(void)
+{
+ int ret;
+ u32 __iomem *tmp_addr;
+
+ watchdog_device.mtmr_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
+
+ /* make sure the timer exists */
+ if (watchdog_device.mtmr_ptr->phy_addr == 0) {
+ pr_debug("Watchdog timer - langwell watchdog - timer %d does"
+ " not valid physical memory\n", sfi_mtimer_num);
+ return -ENODEV;
+ }
+
+ pr_debug("Watchdog timer timer sfi_mtimer_num is %d\n",
+ sfi_mtimer_num);
+ pr_debug("Watchdog timer timer phy_addr is %08x\n",
+ (unsigned int)watchdog_device.mtmr_ptr->phy_addr);
+ pr_debug("Watchdog timer timer IRQ is %d\n",
+ watchdog_device.mtmr_ptr->irq);
+ pr_debug("Watchdog timer timer freq is %d\n",
+ watchdog_device.mtmr_ptr->freq);
+
+ if (watchdog_device.mtmr_ptr->irq == 0) {
+ pr_debug("Watchdog timer - timer %d invalid irq\n",
+ sfi_mtimer_num);
+ return -ENODEV;
+ }
+
+ tmp_addr = ioremap_nocache(watchdog_device.mtmr_ptr->phy_addr, 20);
+
+ if (tmp_addr == NULL) {
+ pr_debug("Watchdog timer timer unable to ioremap\n");
+ return -ENOMEM;
+ }
+
+ watchdog_device.timer_load_count_addr = tmp_addr++;
+ watchdog_device.timer_current_value_addr = tmp_addr++;
+ watchdog_device.timer_control_addr = tmp_addr++;
+ watchdog_device.timer_clear_interrupt_addr = tmp_addr++;
+ watchdog_device.timer_interrupt_status_addr = tmp_addr++;
+
+ pr_debug("Watchdog timer base logical_addr is %08x\n",
+ (unsigned int)tmp_addr);
+ pr_debug("Watchdog timer - watchdog - timer load count is %08x\n",
+ ioread32(watchdog_device.timer_load_count_addr));
+ pr_debug("Watchdog timer - watchdog - timer current value is %08x\n",
+ ioread32(watchdog_device.timer_current_value_addr));
+ pr_debug("Watchdog timer - watchdog - timer control is %08x\n",
+ ioread32(watchdog_device.timer_control_addr));
+
+ watchdog_device.langwell_notifier.notifier_call =
+ langwell_notify_sys;
+
+ ret = register_reboot_notifier(&watchdog_device.langwell_notifier);
+ if (ret) {
+ printk(KERN_ERR PFX
+ "Watchdog timer - cannot register notifier %d)\n", ret);
+ goto register_reboot_error;
+ }
+
+ watchdog_device.miscdev.minor = WATCHDOG_MINOR,
+ watchdog_device.miscdev.name = "watchdog",
+ watchdog_device.miscdev.fops = &langwell_fops,
+
+ ret = misc_register(&watchdog_device.miscdev);
+ if (ret) {
+ printk(KERN_ERR PFX
+ "Watchdog timer - cannot register miscdev %d err =%d\n",
+ WATCHDOG_MINOR,
+ ret);
+ goto misc_register_error;
+ }
+
+ ret = request_irq((unsigned int)watchdog_device.mtmr_ptr->irq,
+ watchdog_timer_interrupt,
+ IRQF_SHARED, "watchdog", &watchdog_device.timer_load_count_addr);
+ if (ret) {
+ printk(KERN_ERR "Watchdog timer - error requesting irq\n");
+ printk(KERN_ERR "Watchdog timer - error value returned is %d\n",
+ ret);
+ goto request_irq_error;
+ }
+
+ return 0;
+
+/* error cleanup */
+
+request_irq_error:
+
+ misc_deregister(&watchdog_device.miscdev);
+
+misc_register_error:
+
+ unregister_reboot_notifier(&watchdog_device.langwell_notifier);
+
+register_reboot_error:
+
+ iounmap(watchdog_device.timer_load_count_addr);
+ return ret;
+}
+
+static void __exit watchdog_exit(void)
+{
+
+ misc_deregister(&watchdog_device.miscdev);
+ unregister_reboot_notifier(&watchdog_device.langwell_notifier);
+ /* disable the timer */
+ iowrite32(0x00000002, watchdog_device.timer_control_addr);
+ iounmap(watchdog_device.timer_load_count_addr);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Langwell Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_VERSION(WDT_VER);
+
diff --git a/drivers/watchdog/langwell_watchdog.h b/drivers/watchdog/langwell_watchdog.h
new file mode 100644
index 0000000..fa4280d
--- /dev/null
+++ b/drivers/watchdog/langwell_watchdog.h
@@ -0,0 +1,60 @@
+/*
+ * Langwell 0.2: An Intel Langwell IOH Based Watchdog Device
+ *
+ * Copyright (C) 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General
+ * Public License 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.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ *
+ */
+
+#ifndef __LANGWELL_WATCHDOG_H
+#define __LANGWELL_WATCHDOG_H
+
+#define PFX "Langwell: "
+#define WDT_VER "0.2"
+
+/* minimum time between interrupts */
+#define MIN_TIME_CYCLE 1
+
+/* Time from warning to reboot is 2 seconds */
+#define DEFAULT_SOFT_TO_HARD_MARGIN 2
+
+#define MAX_TIME 170
+
+#define DEFAULT_TIME 5
+
+#define MAX_SOFT_TO_HARD_MARGIN (MAX_TIME-MIN_TIME_CYCLE)
+
+struct langwell_watchdog_dev {
+ unsigned long driver_open;
+ u32 timer_started;
+ u32 timer_set;
+ u32 threshold;
+ u32 soft_threshold;
+ u32 __iomem *timer_load_count_addr;
+ u32 __iomem *timer_current_value_addr;
+ u32 __iomem *timer_control_addr;
+ u32 __iomem *timer_clear_interrupt_addr;
+ u32 __iomem *timer_interrupt_status_addr;
+ struct sfi_mtimer_entry *mtmr_ptr;
+ struct notifier_block langwell_notifier;
+ struct miscdevice miscdev;
+};
+
+extern int sfi_mtimer_num;
+
+/* extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint); */
+#endif /* __LANGWELL_WATCHDOG_H */
--
1.6.0.6


2010-01-18 21:49:00

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] Add Linux Driver for Intel Langwell Watchdog

Hi Mark,

> This patch adds a Linux device driver for the Intel Langwell
> Watchdog device found on the Intel Mobile Internet device.
>
> The purpose of the watchdog driver is to force a system reboot
> in the event that a critical system process either terminates or
> gets currupted so that it cannot perform its required duties.
>
> This patch is referenced off the linux-next repository as pulled
> on Sunday, January 17, 2010

please skip this message or put it after the diffstat and ---. It has no
useful information as commit message.

If we wanna provide extra details for the person applying these patches,
then after the --- (like the diffstat) is a good place. These are
showing up in the email and the archive, but are not part of the commit
message when the patch gets applied.

> Signed-off-by: Mark Allyn <[email protected]>
>
> Date: January 17, 2010

What is this Date field for?

Regards

Marcel

2010-01-18 22:21:28

by Alan

[permalink] [raw]
Subject: Re: [PATCH] Add Linux Driver for Intel Langwell Watchdog

> + /* send the threshold and soft_threshold via IPC to the Lincroft */
> + reg_data.payload1 = watchdog_device.soft_threshold;
> + reg_data.payload2 = watchdog_device.threshold;
> + ipc_set_watchdog(&reg_data);

That still doesn't seem to be merged upstream - someone needs poking to
at least get an IPC driver into staging.


> + * /dev/watchdog handling
> + */
> +static int langwell_open(struct inode *inode, struct file *file)
> +{
> + /* Miscdevice structure pointer already saved in private_data */
> +
> + struct watchdog_reg_data reg_data;
> +
> + if (!capable(CAP_SYS_ADMIN))
> + return -EPERM;

File permissions will deal with that bit

> +
> + if (test_and_set_bit(0, &watchdog_device.driver_open))
> + return -ENOTTY;

EBUSY

2010-01-19 00:11:34

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] Add Linux Driver for Intel Langwell Watchdog

On Mon, Jan 18, 2010 at 01:24:19PM -0800, Mark Allyn wrote:
> This patch adds a Linux device driver for the Intel Langwell
> Watchdog device found on the Intel Mobile Internet device.

And it breaks the build, so how could we expect to apply it?

Please work to get the needed basic core upstream before adding drivers,
otherwise it just does not work.

thanks,

greg k-h

2010-01-24 23:41:20

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] Add Linux Driver for Intel Langwell Watchdog


> +#include <linux/uaccess.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/sched.h>
> +#include <linux/signal.h>
> +#include <linux/sfi.h>
> +#include <linux/types.h>
> +#include <asm/irq.h>
> +#include <asm/atomic.h>
> +
> +/* See arch/x86/kernel/ipc_mrst.c */
> +#include <asm/ipc_defs.h>

WTF?

> +/* #include <asm/mrst.h> */

remove.

> +MODULE_PARM_DESC(timer_margin,
> + "Watchdog timer margin"
> + "Time between interrupt and resetting the system"
> + "The range is from 1 to 160"
> + "This is the time for all keep alives to arrive");

In miliseconds or what?

> +static int timer_set = DEFAULT_TIME;
> +module_param(timer_set, int, 0);
> +
> +MODULE_PARM_DESC(timer_set,
> + "Default Watchdog timer setting"
> + "Complete cycle time"
> + "The range is from 1 to 170"
> + "This is the time for all keep alives to arrive");
> +
> +/* driver will force boot on closure of device file */
> +static int force_boot = 1;
> +
> +module_param(force_boot, int, 0);
> +MODULE_PARM_DESC(force_boot,
> + "A value of 1 means that the driver will reboot"
> + "the system if the /dev/watchdog device is closed"
> + );

I'd hope watchdogs were somehow standardized?

> +/* This is used to force reboot if anyone tries to close this device */
> +static void watchdog_fire(void)
> +{
> + module_put(THIS_MODULE);

Why?

> + if (force_boot) {
> + printk(KERN_CRIT PFX "Initiating system reboot.\n");
> + emergency_restart();
> + printk(KERN_CRIT PFX "Reboot didn't ?????\n");
> + }
> +
> + else {
> + printk(KERN_CRIT PFX "Reboot would have happend\n");
> + printk(KERN_CRIT PFX "You now have force_boot set to 0\n");
> + printk(KERN_CRIT PFX "I am not rebooting\n");
> + }

Little chatty?

> +/* timer interrupt handler */
> +irqreturn_t watchdog_timer_interrupt(int irq, void *dev_id)
> +{
> + int int_status;
> + int_status = ioread32(watchdog_device.timer_interrupt_status_addr);
> +
> + pr_debug("Watchdog timer - irq 7 interrupt received\n");

is it always irq 7?

> +static int langwell_set_heartbeat(u32 t)
> +{
> + struct watchdog_reg_data reg_data;
> +
> + watchdog_device.timer_set = t;
> + watchdog_device.threshold =
> + timer_margin * watchdog_device.mtmr_ptr->freq;
> + watchdog_device.soft_threshold =
> + (watchdog_device.timer_set - timer_margin)
> + * watchdog_device.mtmr_ptr->freq;
> +
> + pr_debug("Watchdog timer - timer_margin is %x (hex) seconds\n",
> + timer_margin);
> +
> + pr_debug("Watchdog timer - following are in clock cycles\n");
> +
> + pr_debug("Watchdog timer - there are %x (hex) clock cycles\n",
> + watchdog_device.mtmr_ptr->freq);
> +
> + pr_debug("Watchdog timer - per second\n");
> +
> + pr_debug("Watchdog timer - thres is %x (hex) and warm is %x (hex)\n",
> + watchdog_device.threshold, watchdog_device.soft_threshold);
> +
> + pr_debug("Watchdog timer - setting timer_set is %x (hex) seconds\n",
> + watchdog_device.timer_set);

Kill excessive debugging?

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

2010-01-24 23:41:42

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] Add Linux Driver for Intel Langwell Watchdog

> +++ b/drivers/watchdog/Kconfig
> @@ -448,6 +448,13 @@ config IBMASR
> To compile this driver as a module, choose M here: the
> module will be called ibmasr.
>
> +config LANGWELL_WATCHDOG
> + tristate "Intel Langwell Watchdog for Mobil Platforms"

typo?

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html