diff options
| author | Alan Cox <alan@linux.intel.com> | 2012-05-10 15:48:59 -0400 |
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2012-05-30 01:54:25 -0400 |
| commit | 45f5fed30a6460ec58f159ff297a2974153a97de (patch) | |
| tree | d173b2d22ed1187fb7ed2cb85015ddf5c545da05 | |
| parent | fb5f6658163412dce22724e906e324ab7fd62c18 (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.txt | 10 | ||||
| -rw-r--r-- | drivers/watchdog/watchdog_core.c | 43 | ||||
| -rw-r--r-- | drivers/watchdog/watchdog_core.h | 4 | ||||
| -rw-r--r-- | drivers/watchdog/watchdog_dev.c | 127 | ||||
| -rw-r--r-- | include/linux/watchdog.h | 6 |
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 @@ | |||
| 1 | The Linux WatchDog Timer Driver Core kernel API. | 1 | The Linux WatchDog Timer Driver Core kernel API. |
| 2 | =============================================== | 2 | =============================================== |
| 3 | Last reviewed: 16-Mar-2012 | 3 | Last reviewed: 21-May-2012 |
| 4 | 4 | ||
| 5 | Wim Van Sebroeck <wim@iguana.be> | 5 | Wim Van Sebroeck <wim@iguana.be> |
| 6 | 6 | ||
| @@ -39,6 +39,8 @@ watchdog_device structure. | |||
| 39 | The watchdog device structure looks like this: | 39 | The watchdog device structure looks like this: |
| 40 | 40 | ||
| 41 | struct watchdog_device { | 41 | struct 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 | ||
| 52 | It contains following fields: | 54 | It 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 | ||
| 41 | static 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 | */ |
| 50 | int watchdog_register_device(struct watchdog_device *wdd) | 53 | int 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 | } |
| 106 | EXPORT_SYMBOL_GPL(watchdog_unregister_device); | 127 | EXPORT_SYMBOL_GPL(watchdog_unregister_device); |
| 107 | 128 | ||
| 129 | static int __init watchdog_init(void) | ||
| 130 | { | ||
| 131 | return watchdog_dev_init(); | ||
| 132 | } | ||
| 133 | |||
| 134 | static void __exit watchdog_exit(void) | ||
| 135 | { | ||
| 136 | watchdog_dev_exit(); | ||
| 137 | ida_destroy(&watchdog_ida); | ||
| 138 | } | ||
| 139 | |||
| 140 | subsys_initcall(watchdog_init); | ||
| 141 | module_exit(watchdog_exit); | ||
| 142 | |||
| 108 | MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>"); | 143 | MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>"); |
| 109 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); | 144 | MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); |
| 110 | MODULE_DESCRIPTION("WatchDog Timer Driver Core"); | 145 | MODULE_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 | */ |
| 32 | extern int watchdog_dev_register(struct watchdog_device *); | 34 | extern int watchdog_dev_register(struct watchdog_device *); |
| 33 | extern int watchdog_dev_unregister(struct watchdog_device *); | 35 | extern int watchdog_dev_unregister(struct watchdog_device *); |
| 36 | extern int __init watchdog_dev_init(void); | ||
| 37 | extern 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 */ |
| 48 | static unsigned long watchdog_dev_busy; | 48 | static dev_t watchdog_devt; |
| 49 | /* the watchdog device behind /dev/watchdog */ | 49 | /* the watchdog device behind /dev/watchdog */ |
| 50 | static struct watchdog_device *wdd; | 50 | static 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) | |||
| 138 | static ssize_t watchdog_write(struct file *file, const char __user *data, | 138 | static 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 | |||
