Commit fb551405c0f8e15d6fc7ae6e16a5e15382f8b8ac

Authored by Hans de Goede
Committed by Wim Van Sebroeck
1 parent e907df3272

watchdog: sch56xx: Use watchdog core

Convert sch56xx drivers to the generic watchdog core.

Note this patch depends on the "watchdog: Add multiple device support" patch
from Alan Cox.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

Showing 4 changed files with 61 additions and 316 deletions Side-by-side Diff

drivers/hwmon/sch5627.c
... ... @@ -579,7 +579,7 @@
579 579 }
580 580  
581 581 /* Note failing to register the watchdog is not a fatal error */
582   - data->watchdog = sch56xx_watchdog_register(data->addr,
  582 + data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
583 583 (build_code << 24) | (build_id << 8) | hwmon_rev,
584 584 &data->update_lock, 1);
585 585  
drivers/hwmon/sch5636.c
... ... @@ -510,7 +510,7 @@
510 510 }
511 511  
512 512 /* Note failing to register the watchdog is not a fatal error */
513   - data->watchdog = sch56xx_watchdog_register(data->addr,
  513 + data->watchdog = sch56xx_watchdog_register(&pdev->dev, data->addr,
514 514 (revision[0] << 8) | revision[1],
515 515 &data->update_lock, 0);
516 516  
drivers/hwmon/sch56xx-common.c
... ... @@ -66,15 +66,9 @@
66 66  
67 67 struct sch56xx_watchdog_data {
68 68 u16 addr;
69   - u32 revision;
70 69 struct mutex *io_lock;
71   - struct mutex watchdog_lock;
72   - struct list_head list; /* member of the watchdog_data_list */
73   - struct kref kref;
74   - struct miscdevice watchdog_miscdev;
75   - unsigned long watchdog_is_open;
76   - char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
77   - char watchdog_expect_close;
  70 + struct watchdog_info wdinfo;
  71 + struct watchdog_device wddev;
78 72 u8 watchdog_preset;
79 73 u8 watchdog_control;
80 74 u8 watchdog_output_enable;
... ... @@ -82,15 +76,6 @@
82 76  
83 77 static struct platform_device *sch56xx_pdev;
84 78  
85   -/*
86   - * Somewhat ugly :( global data pointer list with all sch56xx devices, so that
87   - * we can find our device data as when using misc_register there is no other
88   - * method to get to ones device data from the open fop.
89   - */
90   -static LIST_HEAD(watchdog_data_list);
91   -/* Note this lock not only protect list access, but also data.kref access */
92   -static DEFINE_MUTEX(watchdog_data_mutex);
93   -
94 79 /* Super I/O functions */
95 80 static inline int superio_inb(int base, int reg)
96 81 {
97 82  
98 83  
... ... @@ -272,22 +257,13 @@
272 257 * Watchdog routines
273 258 */
274 259  
275   -/*
276   - * Release our data struct when the platform device has been released *and*
277   - * all references to our watchdog device are released.
278   - */
279   -static void sch56xx_watchdog_release_resources(struct kref *r)
  260 +static int watchdog_set_timeout(struct watchdog_device *wddev,
  261 + unsigned int timeout)
280 262 {
281   - struct sch56xx_watchdog_data *data =
282   - container_of(r, struct sch56xx_watchdog_data, kref);
283   - kfree(data);
284   -}
285   -
286   -static int watchdog_set_timeout(struct sch56xx_watchdog_data *data,
287   - int timeout)
288   -{
289   - int ret, resolution;
  263 + struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
  264 + unsigned int resolution;
290 265 u8 control;
  266 + int ret;
291 267  
292 268 /* 1 second or 60 second resolution? */
293 269 if (timeout <= 255)
... ... @@ -298,12 +274,6 @@
298 274 if (timeout < resolution || timeout > (resolution * 255))
299 275 return -EINVAL;
300 276  
301   - mutex_lock(&data->watchdog_lock);
302   - if (!data->addr) {
303   - ret = -ENODEV;
304   - goto leave;
305   - }
306   -
307 277 if (resolution == 1)
308 278 control = data->watchdog_control | SCH56XX_WDOG_TIME_BASE_SEC;
309 279 else
... ... @@ -316,7 +286,7 @@
316 286 control);
317 287 mutex_unlock(data->io_lock);
318 288 if (ret)
319   - goto leave;
  289 + return ret;
320 290  
321 291 data->watchdog_control = control;
322 292 }
323 293  
324 294  
325 295  
326 296  
... ... @@ -326,38 +296,17 @@
326 296 * the watchdog countdown.
327 297 */
328 298 data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
  299 + wddev->timeout = data->watchdog_preset * resolution;
329 300  
330   - ret = data->watchdog_preset * resolution;
331   -leave:
332   - mutex_unlock(&data->watchdog_lock);
333   - return ret;
  301 + return 0;
334 302 }
335 303  
336   -static int watchdog_get_timeout(struct sch56xx_watchdog_data *data)
  304 +static int watchdog_start(struct watchdog_device *wddev)
337 305 {
338   - int timeout;
339   -
340   - mutex_lock(&data->watchdog_lock);
341   - if (data->watchdog_control & SCH56XX_WDOG_TIME_BASE_SEC)
342   - timeout = data->watchdog_preset;
343   - else
344   - timeout = data->watchdog_preset * 60;
345   - mutex_unlock(&data->watchdog_lock);
346   -
347   - return timeout;
348   -}
349   -
350   -static int watchdog_start(struct sch56xx_watchdog_data *data)
351   -{
  306 + struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
352 307 int ret;
353 308 u8 val;
354 309  
355   - mutex_lock(&data->watchdog_lock);
356   - if (!data->addr) {
357   - ret = -ENODEV;
358   - goto leave_unlock_watchdog;
359   - }
360   -
361 310 /*
362 311 * The sch56xx's watchdog cannot really be started / stopped
363 312 * it is always running, but we can avoid the timer expiring
364 313  
365 314  
366 315  
367 316  
368 317  
369 318  
370 319  
... ... @@ -405,39 +354,29 @@
405 354  
406 355 leave:
407 356 mutex_unlock(data->io_lock);
408   -leave_unlock_watchdog:
409   - mutex_unlock(&data->watchdog_lock);
410 357 return ret;
411 358 }
412 359  
413   -static int watchdog_trigger(struct sch56xx_watchdog_data *data)
  360 +static int watchdog_trigger(struct watchdog_device *wddev)
414 361 {
  362 + struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
415 363 int ret;
416 364  
417   - mutex_lock(&data->watchdog_lock);
418   - if (!data->addr) {
419   - ret = -ENODEV;
420   - goto leave;
421   - }
422   -
423 365 /* Reset the watchdog countdown counter */
424 366 mutex_lock(data->io_lock);
425 367 ret = sch56xx_write_virtual_reg(data->addr, SCH56XX_REG_WDOG_PRESET,
426 368 data->watchdog_preset);
427 369 mutex_unlock(data->io_lock);
428   -leave:
429   - mutex_unlock(&data->watchdog_lock);
  370 +
430 371 return ret;
431 372 }
432 373  
433   -static int watchdog_stop_unlocked(struct sch56xx_watchdog_data *data)
  374 +static int watchdog_stop(struct watchdog_device *wddev)
434 375 {
  376 + struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
435 377 int ret = 0;
436 378 u8 val;
437 379  
438   - if (!data->addr)
439   - return -ENODEV;
440   -
441 380 if (data->watchdog_output_enable & SCH56XX_WDOG_OUTPUT_ENABLE) {
442 381 val = data->watchdog_output_enable &
443 382 ~SCH56XX_WDOG_OUTPUT_ENABLE;
444 383  
445 384  
... ... @@ -455,184 +394,19 @@
455 394 return ret;
456 395 }
457 396  
458   -static int watchdog_stop(struct sch56xx_watchdog_data *data)
459   -{
460   - int ret;
461   -
462   - mutex_lock(&data->watchdog_lock);
463   - ret = watchdog_stop_unlocked(data);
464   - mutex_unlock(&data->watchdog_lock);
465   -
466   - return ret;
467   -}
468   -
469   -static int watchdog_release(struct inode *inode, struct file *filp)
470   -{
471   - struct sch56xx_watchdog_data *data = filp->private_data;
472   -
473   - if (data->watchdog_expect_close) {
474   - watchdog_stop(data);
475   - data->watchdog_expect_close = 0;
476   - } else {
477   - watchdog_trigger(data);
478   - pr_crit("unexpected close, not stopping watchdog!\n");
479   - }
480   -
481   - clear_bit(0, &data->watchdog_is_open);
482   -
483   - mutex_lock(&watchdog_data_mutex);
484   - kref_put(&data->kref, sch56xx_watchdog_release_resources);
485   - mutex_unlock(&watchdog_data_mutex);
486   -
487   - return 0;
488   -}
489   -
490   -static int watchdog_open(struct inode *inode, struct file *filp)
491   -{
492   - struct sch56xx_watchdog_data *pos, *data = NULL;
493   - int ret, watchdog_is_open;
494   -
495   - /*
496   - * We get called from drivers/char/misc.c with misc_mtx hold, and we
497   - * call misc_register() from sch56xx_watchdog_probe() with
498   - * watchdog_data_mutex hold, as misc_register() takes the misc_mtx
499   - * lock, this is a possible deadlock, so we use mutex_trylock here.
500   - */
501   - if (!mutex_trylock(&watchdog_data_mutex))
502   - return -ERESTARTSYS;
503   - list_for_each_entry(pos, &watchdog_data_list, list) {
504   - if (pos->watchdog_miscdev.minor == iminor(inode)) {
505   - data = pos;
506   - break;
507   - }
508   - }
509   - /* Note we can never not have found data, so we don't check for this */
510   - watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
511   - if (!watchdog_is_open)
512   - kref_get(&data->kref);
513   - mutex_unlock(&watchdog_data_mutex);
514   -
515   - if (watchdog_is_open)
516   - return -EBUSY;
517   -
518   - filp->private_data = data;
519   -
520   - /* Start the watchdog */
521   - ret = watchdog_start(data);
522   - if (ret) {
523   - watchdog_release(inode, filp);
524   - return ret;
525   - }
526   -
527   - return nonseekable_open(inode, filp);
528   -}
529   -
530   -static ssize_t watchdog_write(struct file *filp, const char __user *buf,
531   - size_t count, loff_t *offset)
532   -{
533   - int ret;
534   - struct sch56xx_watchdog_data *data = filp->private_data;
535   -
536   - if (count) {
537   - if (!nowayout) {
538   - size_t i;
539   -
540   - /* Clear it in case it was set with a previous write */
541   - data->watchdog_expect_close = 0;
542   -
543   - for (i = 0; i != count; i++) {
544   - char c;
545   - if (get_user(c, buf + i))
546   - return -EFAULT;
547   - if (c == 'V')
548   - data->watchdog_expect_close = 1;
549   - }
550   - }
551   - ret = watchdog_trigger(data);
552   - if (ret)
553   - return ret;
554   - }
555   - return count;
556   -}
557   -
558   -static long watchdog_ioctl(struct file *filp, unsigned int cmd,
559   - unsigned long arg)
560   -{
561   - struct watchdog_info ident = {
562   - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
563   - .identity = "sch56xx watchdog"
564   - };
565   - int i, ret = 0;
566   - struct sch56xx_watchdog_data *data = filp->private_data;
567   -
568   - switch (cmd) {
569   - case WDIOC_GETSUPPORT:
570   - ident.firmware_version = data->revision;
571   - if (!nowayout)
572   - ident.options |= WDIOF_MAGICCLOSE;
573   - if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
574   - ret = -EFAULT;
575   - break;
576   -
577   - case WDIOC_GETSTATUS:
578   - case WDIOC_GETBOOTSTATUS:
579   - ret = put_user(0, (int __user *)arg);
580   - break;
581   -
582   - case WDIOC_KEEPALIVE:
583   - ret = watchdog_trigger(data);
584   - break;
585   -
586   - case WDIOC_GETTIMEOUT:
587   - i = watchdog_get_timeout(data);
588   - ret = put_user(i, (int __user *)arg);
589   - break;
590   -
591   - case WDIOC_SETTIMEOUT:
592   - if (get_user(i, (int __user *)arg)) {
593   - ret = -EFAULT;
594   - break;
595   - }
596   - ret = watchdog_set_timeout(data, i);
597   - if (ret >= 0)
598   - ret = put_user(ret, (int __user *)arg);
599   - break;
600   -
601   - case WDIOC_SETOPTIONS:
602   - if (get_user(i, (int __user *)arg)) {
603   - ret = -EFAULT;
604   - break;
605   - }
606   -
607   - if (i & WDIOS_DISABLECARD)
608   - ret = watchdog_stop(data);
609   - else if (i & WDIOS_ENABLECARD)
610   - ret = watchdog_trigger(data);
611   - else
612   - ret = -EINVAL;
613   - break;
614   -
615   - default:
616   - ret = -ENOTTY;
617   - }
618   - return ret;
619   -}
620   -
621   -static const struct file_operations watchdog_fops = {
622   - .owner = THIS_MODULE,
623   - .llseek = no_llseek,
624   - .open = watchdog_open,
625   - .release = watchdog_release,
626   - .write = watchdog_write,
627   - .unlocked_ioctl = watchdog_ioctl,
  397 +static const struct watchdog_ops watchdog_ops = {
  398 + .owner = THIS_MODULE,
  399 + .start = watchdog_start,
  400 + .stop = watchdog_stop,
  401 + .ping = watchdog_trigger,
  402 + .set_timeout = watchdog_set_timeout,
628 403 };
629 404  
630   -struct sch56xx_watchdog_data *sch56xx_watchdog_register(
  405 +struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
631 406 u16 addr, u32 revision, struct mutex *io_lock, int check_enabled)
632 407 {
633 408 struct sch56xx_watchdog_data *data;
634   - int i, err, control, output_enable;
635   - const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
  409 + int err, control, output_enable;
636 410  
637 411 /* Cache the watchdog registers */
638 412 mutex_lock(io_lock);
639 413  
640 414  
641 415  
642 416  
643 417  
644 418  
645 419  
646 420  
647 421  
... ... @@ -656,82 +430,53 @@
656 430 return NULL;
657 431  
658 432 data->addr = addr;
659   - data->revision = revision;
660 433 data->io_lock = io_lock;
661   - data->watchdog_control = control;
662   - data->watchdog_output_enable = output_enable;
663   - mutex_init(&data->watchdog_lock);
664   - INIT_LIST_HEAD(&data->list);
665   - kref_init(&data->kref);
666 434  
667   - err = watchdog_set_timeout(data, 60);
668   - if (err < 0)
669   - goto error;
  435 + strlcpy(data->wdinfo.identity, "sch56xx watchdog",
  436 + sizeof(data->wdinfo.identity));
  437 + data->wdinfo.firmware_version = revision;
  438 + data->wdinfo.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT;
  439 + if (!nowayout)
  440 + data->wdinfo.options |= WDIOF_MAGICCLOSE;
670 441  
671   - /*
672   - * We take the data_mutex lock early so that watchdog_open() cannot
673   - * run when misc_register() has completed, but we've not yet added
674   - * our data to the watchdog_data_list.
675   - */
676   - mutex_lock(&watchdog_data_mutex);
677   - for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
678   - /* Register our watchdog part */
679   - snprintf(data->watchdog_name, sizeof(data->watchdog_name),
680   - "watchdog%c", (i == 0) ? '\0' : ('0' + i));
681   - data->watchdog_miscdev.name = data->watchdog_name;
682   - data->watchdog_miscdev.fops = &watchdog_fops;
683   - data->watchdog_miscdev.minor = watchdog_minors[i];
684   - err = misc_register(&data->watchdog_miscdev);
685   - if (err == -EBUSY)
686   - continue;
687   - if (err)
688   - break;
  442 + data->wddev.info = &data->wdinfo;
  443 + data->wddev.ops = &watchdog_ops;
  444 + data->wddev.parent = parent;
  445 + data->wddev.timeout = 60;
  446 + data->wddev.min_timeout = 1;
  447 + data->wddev.max_timeout = 255 * 60;
  448 + if (nowayout)
  449 + data->wddev.status |= WDOG_NO_WAY_OUT;
  450 + if (output_enable & SCH56XX_WDOG_OUTPUT_ENABLE)
  451 + data->wddev.status |= WDOG_ACTIVE;
689 452  
690   - list_add(&data->list, &watchdog_data_list);
691   - pr_info("Registered /dev/%s chardev major 10, minor: %d\n",
692   - data->watchdog_name, watchdog_minors[i]);
693   - break;
694   - }
695   - mutex_unlock(&watchdog_data_mutex);
  453 + /* Since the watchdog uses a downcounter there is no register to read
  454 + the BIOS set timeout from (if any was set at all) ->
  455 + Choose a preset which will give us a 1 minute timeout */
  456 + if (control & SCH56XX_WDOG_TIME_BASE_SEC)
  457 + data->watchdog_preset = 60; /* seconds */
  458 + else
  459 + data->watchdog_preset = 1; /* minute */
696 460  
  461 + data->watchdog_control = control;
  462 + data->watchdog_output_enable = output_enable;
  463 +
  464 + watchdog_set_drvdata(&data->wddev, data);
  465 + err = watchdog_register_device(&data->wddev);
697 466 if (err) {
698 467 pr_err("Registering watchdog chardev: %d\n", err);
699   - goto error;
  468 + kfree(data);
  469 + return NULL;
700 470 }
701   - if (i == ARRAY_SIZE(watchdog_minors)) {
702   - pr_warn("Couldn't register watchdog (no free minor)\n");
703   - goto error;
704   - }
705 471  
706 472 return data;
707   -
708   -error:
709   - kfree(data);
710   - return NULL;
711 473 }
712 474 EXPORT_SYMBOL(sch56xx_watchdog_register);
713 475  
714 476 void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data)
715 477 {
716   - mutex_lock(&watchdog_data_mutex);
717   - misc_deregister(&data->watchdog_miscdev);
718   - list_del(&data->list);
719   - mutex_unlock(&watchdog_data_mutex);
720   -
721   - mutex_lock(&data->watchdog_lock);
722   - if (data->watchdog_is_open) {
723   - pr_warn("platform device unregistered with watchdog "
724   - "open! Stopping watchdog.\n");
725   - watchdog_stop_unlocked(data);
726   - }
727   - /* Tell the wdog start/stop/trigger functions our dev is gone */
728   - data->addr = 0;
729   - data->io_lock = NULL;
730   - mutex_unlock(&data->watchdog_lock);
731   -
732   - mutex_lock(&watchdog_data_mutex);
733   - kref_put(&data->kref, sch56xx_watchdog_release_resources);
734   - mutex_unlock(&watchdog_data_mutex);
  478 + watchdog_unregister_device(&data->wddev);
  479 + kfree(data);
735 480 }
736 481 EXPORT_SYMBOL(sch56xx_watchdog_unregister);
737 482  
drivers/hwmon/sch56xx-common.h
... ... @@ -27,7 +27,7 @@
27 27 int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg,
28 28 int high_nibble);
29 29  
30   -struct sch56xx_watchdog_data *sch56xx_watchdog_register(
  30 +struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
31 31 u16 addr, u32 revision, struct mutex *io_lock, int check_enabled);
32 32 void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data);