Search by Tags

Watchdog (Linux)

 

Compare with Revision




Subscribe for this article updates

A watchdog on Linux is usually exported through a character device under /dev/watchdog. A simple API allows to open device to enable the watchdog. Writing to it triggers the watchdog, and if the device is not cleanly closed, the watchdog will reboot the system.

However, a newer, more feature rich API using ioctrl is available too. We provide a small sample application called watchdog-test. For more information, see: http://git.toradex.com/cgit/linux-toradex.git/tree/Documentation/watchdog/watchdog-api.txt

The kernel configuration option WATCHDOG_NOWAYOUT ("Disable watchdog shutdown on close") gives the userspace application no way to disable the watchdog. Once opened, the application has to trigger the watchdog forever. If the application closes (even it was a "clean close" with a magic character sent), the watchdog will not be disabled. The watchdog can not be disabled using the "WDIOC_SETOPTIONS" ioctl. However, if this option is compiled in the kernel, it can be disabled again using the "nowayout" parameter. In our BSP, this option is not set by default.

NVIDIA Tegra based Modules

NVIDIA Tegra T20/T30 based modules have a built-in hardware watchdog. When the watchdog isn't triggered within the defined period of time (60 seconds by default) the system will reset itself completely (all cores).

In the images 20130305 (T20) and 20130820 (T30) and older contain the official NVidia Watchdog driver. This driver has a different behaviour compared to other Linux watchdog drivers (e.g. PXA aka SA1100 one). The driver resets the watchdog by itself, either writing to /dev/watchdog or doing a WDIOC_KEEPALIVE ioctl on it will not change anything. The userspace device (/dev/watchdog) was not really useful.

By default, our updated driver now behaves as described in the official Watchdog API.

The NVIDIA Tegra T20 based modules support one watchdog available under /dev/watchdog. If this watchdog is used by the kernel level heartbeat (TEGRA_WATCHDOG_ENABLE_HEARTBEAT), it can not be used from userspace.

The NVIDIA Tegra T30 based modules support four watchdogs on the hardware side. However, one watchdog is used kernel internally for suspend mode. Three watchdogs are exported to userspace (/dev/watchdog[0-2]). If the kernel level heartbeat (TEGRA_WATCHDOG_ENABLE_HEARTBEAT) is enabled, the first watchdog can not be used from userspace.

The driver has two parameters:

Parameter Description
nowayout Watchdog cannot be stopped once started
heartbeat Watchdog timeout in seconds (default=60)

Those parameters can be configured in the boot command line with the driver name prepended (tegra_wdt):

tegra_wdt.heartbeat=$seconds

If reboot was due to a watchdog timeout, you will find following message on next boot:

[    4.447307] tegra_wdt tegra_wdt: last reset due to watchdog timeout

Note: The option CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE was renamed to TEGRA_WATCHDOG_ENABLE_HEARTBEAT, which re-enables the watchdog reset by the driver itself (kernel level heartbeat).

Second Note: When using the kernel level heartbeat, the Kernel will not necessarily reboot when a kernel panic occurs since interrupts might still be handled. In order to reboot on kernel panic, use the command line option panic= or the sysctrl.conf option "kernel.panic = ".

i.MX6 and Vybrid based Modules

The NXP/Freescale i.MX6 and Vybrid SoC watchdog is the same hardware as in i.MX2. Because i.MX2 was released earlier, the driver is called imx2-wdt. The watchdog driver creates one device under /dev/watchdog. By default, the watchdog resets the system after 60 seconds.

Parameter Description
nowayout Watchdog cannot be stopped once started
timeout Watchdog timeout in seconds (default=60)

Those parameters can be configured in the boot command line with the driver name prepended (imx2-wdt):

imx2-wdt.timeout=$seconds

i.MX7 based Modules

On the NXP i.MX 7 based modules we make use of the PMIC watchdog, the driver is called rn5t618-wdt. The watchdog driver creates one device under /dev/watchdog. By default, the watchdog resets the system after 128 seconds.

Parameter Description
nowayout Watchdog cannot be stopped once started
timeout Watchdog timeout in seconds (default=128, possible values=1, 8, 32, 128)

Those parameters can be configured in the boot command line with the driver name prepended (rn5t618-wdt):

rn5t618-wdt.timeout=8

Software support

Systemd

Systemd supports hardware watchdogs through the system configuration options RuntimeWatchdogSec and ShutdownWatchdogSec (in /etc/systemd/system.conf). For more information see this blog article about Watchdog support for systemd.

C example

A simple C example which keeps the watchdog fed. After this program gets closed or killed, the system will reboot after the watchdog timeout has expired.

#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/watchdog.h>
 
static int api_watchdog_fd = -1;
 
int api_watchdog_open(const char * watchdog_device)
{
    int ret = -1;
    if (api_watchdog_fd >= 0){
        fprintf(stderr, "Watchdog already opened\n");
        return ret;
    }
    api_watchdog_fd = open(watchdog_device, O_RDWR);
    if (api_watchdog_fd < 0){
        fprintf(stderr, "Could not open %s: %s\n", watchdog_device, strerror(errno));
        return api_watchdog_fd;
    }
    return api_watchdog_fd;
}
 
int api_watchdog_hwfeed(void)
{
    int ret = -1;
    if (api_watchdog_fd < 0){
        fprintf(stderr, "Watchdog must be opened first!\n");
        return ret;
    }
    ret = ioctl(api_watchdog_fd, WDIOC_KEEPALIVE, NULL);
    if (ret < 0){
        fprintf(stderr, "Could not pat watchdog: %s\n", strerror(errno));
    }
    return ret;
}
 
int api_watchdog_init(const char *pcDevice)
{
    printf("Open WatchDog\n");
    int ret = 0;
    ret = api_watchdog_open("/dev/watchdog");
    if(ret < 0){
        return ret;
    }
    ret = api_watchdog_hwfeed();
    return ret;
}
 
int main(int argc, char **argv)
{
    int ret = 0;
    ret = api_watchdog_init("/dev/watchdog");
    if(ret < 0){
        fprintf(stderr, "Could not init watchdog: %s\n", strerror(errno));
    }
    while(1)
    {
        ret = api_watchdog_hwfeed();
        if(ret < 0){
            return ret;
        }
        sleep(1);
    }
}

Refer to the kernel documentation file for more information: watchdog-api.txt