On 11/02/2015 05:36 PM, Damien Riegel wrote:
Many watchdog drivers implement the same code to register a restart
handler. This patch provides a generic way to set such a function.

The patch adds a new restart watchdog operation. If a restart priority
greater than 0 is needed, the driver can call
watchdog_set_restart_priority to set it.

Signed-off-by: Damien Riegel <[email protected]>
Signed-off-by: Vivien Didelot <[email protected]>

Makes sense, and good idea. Unless the patch was written by Vivien,
the second tag should probably be a Reviewed-by: or Acked-by:, though.

Couple of additional comments below.

---
  Documentation/watchdog/watchdog-kernel-api.txt |  2 ++
  drivers/watchdog/watchdog_core.c               | 35 ++++++++++++++++++++++++++
  include/linux/watchdog.h                       |  5 ++++
  3 files changed, 42 insertions(+)

diff --git a/Documentation/watchdog/watchdog-kernel-api.txt 
b/Documentation/watchdog/watchdog-kernel-api.txt
index d8b0d33..10e6132 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -100,6 +100,7 @@ struct watchdog_ops {
        unsigned int (*status)(struct watchdog_device *);
        int (*set_timeout)(struct watchdog_device *, unsigned int);
        unsigned int (*get_timeleft)(struct watchdog_device *);
+       int (*restart)(struct watchdog_device *);
        void (*ref)(struct watchdog_device *);
        void (*unref)(struct watchdog_device *);
        long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
@@ -164,6 +165,7 @@ they are supported. These optional routines/operations are:
    (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
    watchdog's info structure).
  * get_timeleft: this routines returns the time that's left before a reset.
+* restart: this routine restarts the machine.

Please describe the expected return values.
0 - ok, or a negative error value, presumably.

  * ref: the operation that calls kref_get on the kref of a dynamically
    allocated watchdog_device struct.
  * unref: the operation that calls kref_put on the kref of a dynamically
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 873f139..9c8a8e8 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -32,6 +32,7 @@
  #include <linux/types.h>        /* For standard types */
  #include <linux/errno.h>        /* For the -ENODEV/... values */
  #include <linux/kernel.h>       /* For printk/panic/... */
+#include <linux/reboot.h>        /* For restart handler */
  #include <linux/watchdog.h>     /* For watchdog specific items */
  #include <linux/init.h>         /* For __init/__exit/... */
  #include <linux/idr.h>          /* For ida_* macros */
@@ -137,6 +138,28 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
  }
  EXPORT_SYMBOL_GPL(watchdog_init_timeout);

+static int watchdog_restart_notifier(struct notifier_block *nb,
+                                    unsigned long action, void *data)
+{
+       struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
+                                                  restart_nb);
+
+       int ret;
+
+       ret = wdd->ops->restart(wdd);
+       if (ret)
+               return NOTIFY_BAD;
+
+       return NOTIFY_DONE;
+}
+
+void watchdog_set_restart_priority(struct watchdog_device *wdd,
+                                  int priority)

Fits one line.

+{
+       wdd->restart_nb.priority = priority;
+}
+EXPORT_SYMBOL_GPL(watchdog_set_restart_priority);
+
  static int __watchdog_register_device(struct watchdog_device *wdd)
  {
        int ret, id = -1, devno;
@@ -202,6 +225,15 @@ static int __watchdog_register_device(struct 
watchdog_device *wdd)
                return ret;
        }

+       if (wdd->ops->restart) {
+               wdd->restart_nb.notifier_call = watchdog_restart_notifier;
+
+               ret = register_restart_handler(&wdd->restart_nb);
+               if (ret)
+                       dev_err(wdd->dev, "Cannot register restart handler 
(%d)\n",
+                               ret);

dev_warn, please.

+       }
+
        return 0;
  }

@@ -238,6 +270,9 @@ static void __watchdog_unregister_device(struct 
watchdog_device *wdd)
        if (wdd == NULL)
                return;

+       if (wdd->ops->restart)
+               unregister_restart_handler(&wdd->restart_nb);
+
        devno = wdd->cdev.dev;
        ret = watchdog_dev_unregister(wdd);
        if (ret)
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index e90e3ea..e1a4dc4 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -26,6 +26,7 @@ struct watchdog_device;
   * @status:   The routine that shows the status of the watchdog device.
   * @set_timeout:The routine for setting the watchdog devices timeout value.
   * @get_timeleft:The routine that get's the time that's left before a reset.
+ * @restart:   The routine for restarting the machine.
   * @ref:      The ref operation for dyn. allocated watchdog_device structs
   * @unref:    The unref operation for dyn. allocated watchdog_device structs
   * @ioctl:    The routines that handles extra ioctl calls.
@@ -45,6 +46,7 @@ struct watchdog_ops {
        unsigned int (*status)(struct watchdog_device *);
        int (*set_timeout)(struct watchdog_device *, unsigned int);
        unsigned int (*get_timeleft)(struct watchdog_device *);
+       int (*restart)(struct watchdog_device *);
        void (*ref)(struct watchdog_device *);
        void (*unref)(struct watchdog_device *);
        long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
@@ -88,6 +90,7 @@ struct watchdog_device {
        unsigned int timeout;
        unsigned int min_timeout;
        unsigned int max_timeout;
+       struct notifier_block restart_nb;
        void *driver_data;
        struct mutex lock;
        unsigned long status;
@@ -142,6 +145,8 @@ static inline void *watchdog_get_drvdata(struct 
watchdog_device *wdd)
  }

  /* drivers/watchdog/watchdog_core.c */
+extern void watchdog_set_restart_priority(struct watchdog_device *wdd,
+                                         int priority);

extern is unnecessary (yes, we'll need to fix that for the other exported
functions, but no need to introduce new ones), and then it fits one line.

  extern int watchdog_init_timeout(struct watchdog_device *wdd,
                                  unsigned int timeout_parm, struct device 
*dev);
  extern int watchdog_register_device(struct watchdog_device *);


--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to