aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2012-05-10 15:48:59 -0400
committerWim Van Sebroeck <wim@iguana.be>2012-05-30 01:54:25 -0400
commit45f5fed30a6460ec58f159ff297a2974153a97de (patch)
treed173b2d22ed1187fb7ed2cb85015ddf5c545da05
parentfb5f6658163412dce22724e906e324ab7fd62c18 (diff)
watchdog: Add multiple device support
We keep the old /dev/watchdog interface file for the first watchdog via miscdev. This is basically a cut and paste of the relevant interface code from the rtc driver layer tweaked for watchdog. Revised to fix problems noted by Hans de Goede Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--Documentation/watchdog/watchdog-kernel-api.txt10
-rw-r--r--drivers/watchdog/watchdog_core.c43
-rw-r--r--drivers/watchdog/watchdog_core.h4
-rw-r--r--drivers/watchdog/watchdog_dev.c127
-rw-r--r--include/linux/watchdog.h6
5 files changed, 140 insertions, 50 deletions
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index 25fe4304f2fc..3c85fc7dc1f1 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -1,6 +1,6 @@
1The Linux WatchDog Timer Driver Core kernel API. 1The Linux WatchDog Timer Driver Core kernel API.
2=============================================== 2===============================================
3Last reviewed: 16-Mar-2012 3Last reviewed: 21-May-2012
4 4
5Wim Van Sebroeck <wim@iguana.be> 5Wim Van Sebroeck <wim@iguana.be>
6 6
@@ -39,6 +39,8 @@ watchdog_device structure.
39The watchdog device structure looks like this: 39The watchdog device structure looks like this:
40 40
41struct watchdog_device { 41struct watchdog_device {
42 int id;
43 struct cdev cdev;
42 const struct watchdog_info *info; 44 const struct watchdog_info *info;
43 const struct watchdog_ops *ops; 45 const struct watchdog_ops *ops;
44 unsigned int bootstatus; 46 unsigned int bootstatus;
@@ -50,6 +52,12 @@ struct watchdog_device {
50}; 52};
51 53
52It contains following fields: 54It contains following fields:
55* id: set by watchdog_register_device, id 0 is special. It has both a
56 /dev/watchdog0 cdev (dynamic major, minor 0) as well as the old
57 /dev/watchdog miscdev. The id is set automatically when calling
58 watchdog_register_device.
59* cdev: cdev for the dynamic /dev/watchdog<id> device nodes. This
60 field is also populated by watchdog_register_device.
53* info: a pointer to a watchdog_info structure. This structure gives some 61* info: a pointer to a watchdog_info structure. This structure gives some
54 additional information about the watchdog timer itself. (Like it's unique name) 62 additional information about the watchdog timer itself. (Like it's unique name)
55* ops: a pointer to the list of watchdog operations that the watchdog supports. 63* ops: a pointer to the list of watchdog operations that the watchdog supports.
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 8598308278d3..5f9879369003 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -34,9 +34,12 @@
34#include <linux/kernel.h> /* For printk/panic/... */ 34#include <linux/kernel.h> /* For printk/panic/... */
35#include <linux/watchdog.h> /* For watchdog specific items */ 35#include <linux/watchdog.h> /* For watchdog specific items */
36#include <linux/init.h> /* For __init/__exit/... */ 36#include <linux/init.h> /* For __init/__exit/... */
37#include <linux/idr.h> /* For ida_* macros */
37 38
38#include "watchdog_core.h" /* For watchdog_dev_register/... */ 39#include "watchdog_core.h" /* For watchdog_dev_register/... */
39 40
41static DEFINE_IDA(watchdog_ida);
42
40/** 43/**
41 * watchdog_register_device() - register a watchdog device 44 * watchdog_register_device() - register a watchdog device
42 * @wdd: watchdog device 45 * @wdd: watchdog device
@@ -49,7 +52,7 @@
49 */ 52 */
50int watchdog_register_device(struct watchdog_device *wdd) 53int watchdog_register_device(struct watchdog_device *wdd)
51{ 54{
52 int ret; 55 int ret, id;
53 56
54 if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL) 57 if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
55 return -EINVAL; 58 return -EINVAL;
@@ -74,11 +77,28 @@ int watchdog_register_device(struct watchdog_device *wdd)
74 * corrupted in a later stage then we expect a kernel panic! 77 * corrupted in a later stage then we expect a kernel panic!
75 */ 78 */
76 79
77 /* We only support 1 watchdog device via the /dev/watchdog interface */ 80 id = ida_simple_get(&watchdog_ida, 0, MAX_DOGS, GFP_KERNEL);
81 if (id < 0)
82 return id;
83 wdd->id = id;
84
78 ret = watchdog_dev_register(wdd); 85 ret = watchdog_dev_register(wdd);
79 if (ret) { 86 if (ret) {
80 pr_err("error registering /dev/watchdog (err=%d)\n", ret); 87 ida_simple_remove(&watchdog_ida, id);
81 return ret; 88 if (!(id == 0 && ret == -EBUSY))
89 return ret;
90
91 /* Retry in case a legacy watchdog module exists */
92 id = ida_simple_get(&watchdog_ida, 1, MAX_DOGS, GFP_KERNEL);
93 if (id < 0)
94 return id;
95 wdd->id = id;
96
97 ret = watchdog_dev_register(wdd);
98 if (ret) {
99 ida_simple_remove(&watchdog_ida, id);
100 return ret;
101 }
82 } 102 }
83 103
84 return 0; 104 return 0;
@@ -102,9 +122,24 @@ void watchdog_unregister_device(struct watchdog_device *wdd)
102 ret = watchdog_dev_unregister(wdd); 122 ret = watchdog_dev_unregister(wdd);
103 if (ret) 123 if (ret)
104 pr_err("error unregistering /dev/watchdog (err=%d)\n", ret); 124 pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
125 ida_simple_remove(&watchdog_ida, wdd->id);
105} 126}
106EXPORT_SYMBOL_GPL(watchdog_unregister_device); 127EXPORT_SYMBOL_GPL(watchdog_unregister_device);
107 128
129static int __init watchdog_init(void)
130{
131 return watchdog_dev_init();
132}
133
134static void __exit watchdog_exit(void)
135{
136 watchdog_dev_exit();
137 ida_destroy(&watchdog_ida);
138}
139
140subsys_initcall(watchdog_init);
141module_exit(watchdog_exit);
142
108MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>"); 143MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
109MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); 144MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
110MODULE_DESCRIPTION("WatchDog Timer Driver Core"); 145MODULE_DESCRIPTION("WatchDog Timer Driver Core");
diff --git a/drivers/watchdog/watchdog_core.h b/drivers/watchdog/watchdog_core.h
index 80503f229385..6c951418fca7 100644
--- a/drivers/watchdog/watchdog_core.h
+++ b/drivers/watchdog/watchdog_core.h
@@ -26,8 +26,12 @@
26 * This material is provided "AS-IS" and at no charge. 26 * This material is provided "AS-IS" and at no charge.
27 */ 27 */
28 28
29#define MAX_DOGS 32 /* Maximum number of watchdog devices */
30
29/* 31/*
30 * Functions/procedures to be called by the core 32 * Functions/procedures to be called by the core
31 */ 33 */
32extern int watchdog_dev_register(struct watchdog_device *); 34extern int watchdog_dev_register(struct watchdog_device *);
33extern int watchdog_dev_unregister(struct watchdog_device *); 35extern int watchdog_dev_unregister(struct watchdog_device *);
36extern int __init watchdog_dev_init(void);
37extern void __exit watchdog_dev_exit(void);
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index beaf9cb5541a..3b22582bcb04 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -44,10 +44,10 @@
44 44
45#include "watchdog_core.h" 45#include "watchdog_core.h"
46 46
47/* make sure we only register one /dev/watchdog device */ 47/* the dev_t structure to store the dynamically allocated watchdog devices */
48static unsigned long watchdog_dev_busy; 48static dev_t watchdog_devt;
49/* the watchdog device behind /dev/watchdog */ 49/* the watchdog device behind /dev/watchdog */
50static struct watchdog_device *wdd; 50static struct watchdog_device *old_wdd;
51 51
52/* 52/*
53 * watchdog_ping: ping the watchdog. 53 * watchdog_ping: ping the watchdog.
@@ -138,6 +138,7 @@ static int watchdog_stop(struct watchdog_device *wddev)
138static ssize_t watchdog_write(struct file *file, const char __user *data, 138static ssize_t watchdog_write(struct file *file, const char __user *data,
139 size_t len, loff_t *ppos) 139 size_t len, loff_t *ppos)
140{ 140{
141 struct watchdog_device *wdd = file->private_data;
141 size_t i; 142 size_t i;
142 char c; 143 char c;
143