aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/watchdog/watchdog_core.c43
-rw-r--r--drivers/watchdog/watchdog_core.h4
-rw-r--r--drivers/watchdog/watchdog_dev.c127
3 files changed, 125 insertions, 49 deletions
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}