Skip to content

Commit

Permalink
watchdog: WatchDog Timer Driver Core - Add basic framework
Browse files Browse the repository at this point in the history
The WatchDog Timer Driver Core is a framework
that contains the common code for all watchdog-driver's.
It also introduces a watchdog device structure and the
operations that go with it.

This is the introduction of this framework. This part
supports the minimal watchdog userspace API (or with
other words: the functionality to use /dev/watchdog's
open, release and write functionality as defined in
the simplest watchdog API). Extra functionality will
follow in the next set of patches.

Signed-off-by: Alan Cox <[email protected]>
Signed-off-by: Wim Van Sebroeck <[email protected]>
Acked-by: Arnd Bergmann <[email protected]>
Acked-by: Wolfram Sang <[email protected]>
  • Loading branch information
Wim Van Sebroeck committed Jul 28, 2011
1 parent 5efc7a6 commit 4331604
Show file tree
Hide file tree
Showing 8 changed files with 566 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Documentation/watchdog/00-INDEX
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ src/
- directory holding watchdog related example programs.
watchdog-api.txt
- description of the Linux Watchdog driver API.
watchdog-kernel-api.txt
- description of the Linux WatchDog Timer Driver Core kernel API.
watchdog-parameters.txt
- information on driver parameters (for drivers other than
the ones that have driver-specific files here)
Expand Down
119 changes: 119 additions & 0 deletions Documentation/watchdog/watchdog-kernel-api.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
The Linux WatchDog Timer Driver Core kernel API.
===============================================
Last reviewed: 22-Jul-2011

Wim Van Sebroeck <[email protected]>

Introduction
------------
This document does not describe what a WatchDog Timer (WDT) Driver or Device is.
It also does not describe the API which can be used by user space to communicate
with a WatchDog Timer. If you want to know this then please read the following
file: Documentation/watchdog/watchdog-api.txt .

So what does this document describe? It describes the API that can be used by
WatchDog Timer Drivers that want to use the WatchDog Timer Driver Core
Framework. This framework provides all interfacing towards user space so that
the same code does not have to be reproduced each time. This also means that
a watchdog timer driver then only needs to provide the different routines
(operations) that control the watchdog timer (WDT).

The API
-------
Each watchdog timer driver that wants to use the WatchDog Timer Driver Core
must #include <linux/watchdog.h> (you would have to do this anyway when
writing a watchdog device driver). This include file contains following
register/unregister routines:

extern int watchdog_register_device(struct watchdog_device *);
extern void watchdog_unregister_device(struct watchdog_device *);

The watchdog_register_device routine registers a watchdog timer device.
The parameter of this routine is a pointer to a watchdog_device structure.
This routine returns zero on success and a negative errno code for failure.

The watchdog_unregister_device routine deregisters a registered watchdog timer
device. The parameter of this routine is the pointer to the registered
watchdog_device structure.

The watchdog device structure looks like this:

struct watchdog_device {
const struct watchdog_info *info;
const struct watchdog_ops *ops;
void *driver_data;
unsigned long status;
};

It contains following fields:
* info: a pointer to a watchdog_info structure. This structure gives some
additional information about the watchdog timer itself. (Like it's unique name)
* ops: a pointer to the list of watchdog operations that the watchdog supports.
* driver_data: a pointer to the drivers private data of a watchdog device.
This data should only be accessed via the watchdog_set_drvadata and
watchdog_get_drvdata routines.
* status: this field contains a number of status bits that give extra
information about the status of the device (Like: is the device opened via
the /dev/watchdog interface or not, ...).

The list of watchdog operations is defined as:

struct watchdog_ops {
struct module *owner;
/* mandatory operations */
int (*start)(struct watchdog_device *);
int (*stop)(struct watchdog_device *);
/* optional operations */
int (*ping)(struct watchdog_device *);
};

It is important that you first define the module owner of the watchdog timer
driver's operations. This module owner will be used to lock the module when
the watchdog is active. (This to avoid a system crash when you unload the
module and /dev/watchdog is still open).
Some operations are mandatory and some are optional. The mandatory operations
are:
* start: this is a pointer to the routine that starts the watchdog timer
device.
The routine needs a pointer to the watchdog timer device structure as a
parameter. It returns zero on success or a negative errno code for failure.
* stop: with this routine the watchdog timer device is being stopped.
The routine needs a pointer to the watchdog timer device structure as a
parameter. It returns zero on success or a negative errno code for failure.
Some watchdog timer hardware can only be started and not be stopped. The
driver supporting this hardware needs to make sure that a start and stop
routine is being provided. This can be done by using a timer in the driver
that regularly sends a keepalive ping to the watchdog timer hardware.

Not all watchdog timer hardware supports the same functionality. That's why
all other routines/operations are optional. They only need to be provided if
they are supported. These optional routines/operations are:
* ping: this is the routine that sends a keepalive ping to the watchdog timer
hardware.
The routine needs a pointer to the watchdog timer device structure as a
parameter. It returns zero on success or a negative errno code for failure.
Most hardware that does not support this as a separate function uses the
start function to restart the watchdog timer hardware. And that's also what
the watchdog timer driver core does: to send a keepalive ping to the watchdog
timer hardware it will either use the ping operation (when available) or the
start operation (when the ping operation is not available).

The status bits should (preferably) be set with the set_bit and clear_bit alike
bit-operations. The status bits that are defined are:
* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
was opened via /dev/watchdog.
(This bit should only be used by the WatchDog Timer Driver Core).

To get or set driver specific data the following two helper functions should be
used:

static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)

The watchdog_set_drvdata function allows you to add driver specific data. The
arguments of this function are the watchdog device where you want to add the
driver specific data to and a pointer to the data itself.

The watchdog_get_drvdata function allows you to retrieve driver specific data.
The argument of this function is the watchdog device where you want to retrieve
data from. The function retruns the pointer to the driver specific data.
11 changes: 11 additions & 0 deletions drivers/watchdog/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ menuconfig WATCHDOG

if WATCHDOG

config WATCHDOG_CORE
bool "WatchDog Timer Driver Core"
---help---
Say Y here if you want to use the new watchdog timer driver core.
This driver provides a framework for all watchdog timer drivers
and gives them the /dev/watchdog interface (and later also the
sysfs interface).

To compile this driver as a module, choose M here: the module will
be called watchdog.

config WATCHDOG_NOWAYOUT
bool "Disable watchdog shutdown on close"
help
Expand Down
4 changes: 4 additions & 0 deletions drivers/watchdog/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
# Makefile for the WatchDog device drivers.
#

# The WatchDog Timer Driver Core.
watchdog-objs += watchdog_core.o watchdog_dev.o
obj-$(CONFIG_WATCHDOG_CORE) += watchdog.o

# Only one watchdog can succeed. We probe the ISA/PCI/USB based
# watchdog-cards first, then the architecture specific watchdog
# drivers and then the architecture independent "softdog" driver.
Expand Down
101 changes: 101 additions & 0 deletions drivers/watchdog/watchdog_core.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* watchdog_core.c
*
* (c) Copyright 2008-2011 Alan Cox <[email protected]>,
* All Rights Reserved.
*
* (c) Copyright 2008-2011 Wim Van Sebroeck <[email protected]>.
*
* This source code is part of the generic code that can be used
* by all the watchdog timer drivers.
*
* Based on source code of the following authors:
* Matt Domsch <[email protected]>,
* Rob Radez <[email protected]>,
* Rusty Lynch <[email protected]>
* Satyam Sharma <[email protected]>
* Randy Dunlap <[email protected]>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
* admit liability nor provide warranty for any of this software.
* This material is provided "AS-IS" and at no charge.
*/

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h> /* For EXPORT_SYMBOL/module stuff/... */
#include <linux/types.h> /* For standard types */
#include <linux/errno.h> /* For the -ENODEV/... values */
#include <linux/kernel.h> /* For printk/panic/... */
#include <linux/watchdog.h> /* For watchdog specific items */
#include <linux/init.h> /* For __init/__exit/... */

#include "watchdog_dev.h" /* For watchdog_dev_register/... */

/**
* watchdog_register_device() - register a watchdog device
* @wdd: watchdog device
*
* Register a watchdog device with the kernel so that the
* watchdog timer can be accessed from userspace.
*
* A zero is returned on success and a negative errno code for
* failure.
*/
int watchdog_register_device(struct watchdog_device *wdd)
{
int ret;

if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
return -EINVAL;

/* Mandatory operations need to be supported */
if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
return -EINVAL;

/*
* Note: now that all watchdog_device data has been verified, we
* will not check this anymore in other functions. If data gets
* corrupted in a later stage then we expect a kernel panic!
*/

/* We only support 1 watchdog device via the /dev/watchdog interface */
ret = watchdog_dev_register(wdd);
if (ret) {
pr_err("error registering /dev/watchdog (err=%d).\n", ret);
return ret;
}

return 0;
}
EXPORT_SYMBOL_GPL(watchdog_register_device);

/**
* watchdog_unregister_device() - unregister a watchdog device
* @wdd: watchdog device to unregister
*
* Unregister a watchdog device that was previously successfully
* registered with watchdog_register_device().
*/
void watchdog_unregister_device(struct watchdog_device *wdd)
{
int ret;

if (wdd == NULL)
return;

ret = watchdog_dev_unregister(wdd);
if (ret)
pr_err("error unregistering /dev/watchdog (err=%d).\n", ret);
}
EXPORT_SYMBOL_GPL(watchdog_unregister_device);

MODULE_AUTHOR("Alan Cox <[email protected]>");
MODULE_AUTHOR("Wim Van Sebroeck <[email protected]>");
MODULE_DESCRIPTION("WatchDog Timer Driver Core");
MODULE_LICENSE("GPL");
Loading

0 comments on commit 4331604

Please sign in to comment.