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 144
@@ -177,6 +178,7 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
177static long watchdog_ioctl(struct file *file, unsigned int cmd, 178static long watchdog_ioctl(struct file *file, unsigned int cmd,
178 unsigned long arg) 179 unsigned long arg)
179{ 180{
181 struct watchdog_device *wdd = file->private_data;
180 void __user *argp = (void __user *)arg; 182 void __user *argp = (void __user *)arg;
181 int __user *p = argp; 183 int __user *p = argp;
182 unsigned int val; 184 unsigned int val;
@@ -249,11 +251,11 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
249} 251}
250 252
251/* 253/*
252 * watchdog_open: open the /dev/watchdog device. 254 * watchdog_open: open the /dev/watchdog* devices.
253 * @inode: inode of device 255 * @inode: inode of device
254 * @file: file handle to device 256 * @file: file handle to device
255 * 257 *
256 * When the /dev/watchdog device gets opened, we start the watchdog. 258 * When the /dev/watchdog* device gets opened, we start the watchdog.
257 * Watch out: the /dev/watchdog device is single open, so we make sure 259 * Watch out: the /dev/watchdog device is single open, so we make sure
258 * it can only be opened once. 260 * it can only be opened once.
259 */ 261 */
@@ -261,6 +263,13 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
261static int watchdog_open(struct inode *inode, struct file *file) 263static int watchdog_open(struct inode *inode, struct file *file)
262{ 264{
263 int err = -EBUSY; 265 int err = -EBUSY;
266 struct watchdog_device *wdd;
267
268 /* Get the corresponding watchdog device */
269 if (imajor(inode) == MISC_MAJOR)
270 wdd = old_wdd;
271 else
272 wdd = container_of(inode->i_cdev, struct watchdog_device, cdev);
264 273
265 /* the watchdog is single open! */ 274 /* the watchdog is single open! */
266 if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status)) 275 if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
@@ -277,6 +286,8 @@ static int watchdog_open(struct inode *inode, struct file *file)
277 if (err < 0) 286 if (err < 0)
278 goto out_mod; 287 goto out_mod;
279 288
289 file->private_data = wdd;
290
280 /* dev/watchdog is a virtual (and thus non-seekable) filesystem */ 291 /* dev/watchdog is a virtual (and thus non-seekable) filesystem */
281 return nonseekable_open(inode, file); 292 return nonseekable_open(inode, file);
282 293
@@ -288,9 +299,9 @@ out:
288} 299}
289 300
290/* 301/*
291 * watchdog_release: release the /dev/watchdog device. 302 * watchdog_release: release the watchdog device.
292 * @inode: inode of device 303 * @inode: inode of device
293 * @file: file handle to device 304 * @file: file handle to device
294 * 305 *
295 * This is the code for when /dev/watchdog gets closed. We will only 306 * This is the code for when /dev/watchdog gets closed. We will only
296 * stop the watchdog when we have received the magic char (and nowayout 307 * stop the watchdog when we have received the magic char (and nowayout
@@ -299,6 +310,7 @@ out:
299 310
300static int watchdog_release(struct inode *inode, struct file *file) 311static int watchdog_release(struct inode *inode, struct file *file)
301{ 312{
313 struct watchdog_device *wdd = file->private_data;
302 int err = -EBUSY; 314 int err = -EBUSY;
303 315
304 /* 316 /*
@@ -340,62 +352,87 @@ static struct miscdevice watchdog_miscdev = {
340}; 352};
341 353
342/* 354/*
343 * watchdog_dev_register: 355 * watchdog_dev_register: register a watchdog device
344 * @watchdog: watchdog device 356 * @watchdog: watchdog device
345 * 357 *
346 * Register a watchdog device as /dev/watchdog. /dev/watchdog 358 * Register a watchdog device including handling the legacy
347 * is actually a miscdevice and thus we set it up like that. 359 * /dev/watchdog node. /dev/watchdog is actually a miscdevice and
360 * thus we set it up like that.
348 */ 361 */
349 362
350int watchdog_dev_register(struct watchdog_device *watchdog) 363int watchdog_dev_register(struct watchdog_device *watchdog)
351{ 364{
352 int err; 365 int err, devno;
353 366
354 /* Only one device can register for /dev/watchdog */ 367 if (watchdog->id == 0) {
355 if (test_and_set_bit(0, &watchdog_dev_busy)) { 368 err = misc_register(&watchdog_miscdev);
356 pr_err("only one watchdog can use /dev/watchdog\n"); 369 if (err != 0) {
357 return -EBUSY; 370 pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
371 watchdog->info->identity, WATCHDOG_MINOR, err);
372 if (err == -EBUSY)
373 pr_err("%s: a legacy watchdog module is probably present.\n",
374 watchdog->info->identity);
375 return err;
376 }
377 old_wdd = watchdog;
358 } 378 }
359 379
360 wdd = watchdog; 380 /* Fill in the data structures */
361 381 devno = MKDEV(MAJOR(watchdog_devt), watchdog->id);
362 err = misc_register(&watchdog_miscdev); 382 cdev_init(&watchdog->cdev, &watchdog_fops);
363 if (err != 0) { 383 watchdog->cdev.owner = watchdog->ops->owner;
364 pr_err("%s: cannot register miscdev on minor=%d (err=%d)\n", 384
365 watchdog->info->identity, WATCHDOG_MINOR, err); 385 /* Add the device */
366 goto out; 386 err = cdev_add(&watchdog->cdev, devno, 1);
387 if (err) {
388 pr_err("watchdog%d unable to add device %d:%d\n",
389 watchdog->id, MAJOR(watchdog_devt), watchdog->id);
390 if (watchdog->id == 0) {
391 misc_deregister(&watchdog_miscdev);
392 old_wdd = NULL;
393 }
367 } 394 }
368
369 return 0;
370
371out:
372 wdd = NULL;
373 clear_bit(0, &watchdog_dev_busy);
374 return err; 395 return err;
375} 396}
376 397
377/* 398/*
378 * watchdog_dev_unregister: 399 * watchdog_dev_unregister: unregister a watchdog device
379 * @watchdog: watchdog device 400 * @watchdog: watchdog device
380 * 401 *
381 * Deregister the /dev/watchdog device. 402 * Unregister the watchdog and if needed the legacy /dev/watchdog device.
382 */ 403 */
383 404
384int watchdog_dev_unregister(struct watchdog_device *watchdog) 405int watchdog_dev_unregister(struct watchdog_device *watchdog)
385{ 406{
386 /* Check that a watchdog device was registered in the past */ 407 cdev_del(&watchdog->cdev);
387 if (!test_bit(0, &watchdog_dev_busy) || !wdd) 408 if (watchdog->id == 0) {
388 return -ENODEV; 409 misc_deregister(&watchdog_miscdev);
389 410 old_wdd = NULL;
390 /* We can only unregister the watchdog device that was registered */
391 if (watchdog != wdd) {
392 pr_err("%s: watchdog was not registered as /dev/watchdog\n",
393 watchdog->info->identity);
394 return -ENODEV;
395 } 411 }
396
397 misc_deregister(&watchdog_miscdev);
398 wdd = NULL;
399 clear_bit(0, &watchdog_dev_busy);
400 return 0; 412 return 0;
401} 413}
414
415/*
416 * watchdog_dev_init: init dev part of watchdog core
417 *
418 * Allocate a range of chardev nodes to use for watchdog devices
419 */
420
421int __init watchdog_dev_init(void)
422{
423 int err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
424 if (err < 0)
425 pr_err("watchdog: unable to allocate char dev region\n");
426 return err;
427}
428
429/*
430 * watchdog_dev_exit: exit dev part of watchdog core
431 *
432 * Release the range of chardev nodes used for watchdog devices
433 */
434
435void __exit watchdog_dev_exit(void)
436{
437 unregister_chrdev_region(watchdog_devt, MAX_DOGS);
438}
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 1984ea610577..508d56399e6d 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -54,6 +54,8 @@ struct watchdog_info {
54#ifdef __KERNEL__ 54#ifdef __KERNEL__
55 55
56#include <linux/bitops.h> 56#include <linux/bitops.h>
57#include <linux/device.h>
58#include <linux/cdev.h>
57 59
58struct watchdog_ops; 60struct watchdog_ops;
59struct watchdog_device; 61struct watchdog_device;
@@ -89,6 +91,8 @@ struct watchdog_ops {
89 91
90/** struct watchdog_device - The structure that defines a watchdog device 92/** struct watchdog_device - The structure that defines a watchdog device
91 * 93 *
94 * @id: The watchdog's ID. (Allocated by watchdog_register_device)
95 * @cdev: The watchdog's Character device.
92 * @info: Pointer to a watchdog_info structure. 96 * @info: Pointer to a watchdog_info structure.
93 * @ops: Pointer to the list of watchdog operations. 97 * @ops: Pointer to the list of watchdog operations.
94 * @bootstatus: Status of the watchdog device at boot. 98 * @bootstatus: Status of the watchdog device at boot.
@@ -105,6 +109,8 @@ struct watchdog_ops {
105 * via the watchdog_set_drvdata and watchdog_get_drvdata helpers. 109 * via the watchdog_set_drvdata and watchdog_get_drvdata helpers.
106 */ 110 */
107struct watchdog_device { 111struct watchdog_device {
112 int id;
113 struct cdev cdev;
108 const struct watchdog_info *info; 114 const struct watchdog_info *info;
109 const struct watchdog_ops *ops; 115 const struct watchdog_ops *ops;
110 unsigned int bootstatus; 116 unsigned int bootstatus;