Watchdog (Linux)
Introduction
A watchdog on Linux is usually exported through a character device under /dev/watchdog. A simple API allows opening the 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: https://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 cannot 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.
Hardware Support
See information about specific Toradex modules in this section.
i.MX 6, i.MX 6ULL and i.MX 8M Mini/Plus based modules
The NXP/Freescale i.MX6 SoC watchdog is the same hardware as in the i.MX2. Because of the i.MX2 having been 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 U-Boot environment bootargs, which is used to pass commands to the Linux kernel, with the driver name prepended (imx2-wdt):
imx2-wdt.timeout=$seconds
The respective boot environment needs to be configured on U-Boot since it passes some arguments to the Linux kernel using the bootargs environment variable.
i.MX 7 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 U-Boot environment bootargs, which is used to pass commands to the Linux kernel, with the driver name prepended (rn5t618-wdt):
rn5t618-wdt.timeout=8
The respective boot environment needs to be configured on U-Boot since it passes some arguments to the Linux kernel using the bootargs environment variable.
Readout Reset Reason
Usually the reset reason of the module is shown either in U-Boot or Linux Kernel console messages, so user can identify if the SoM was reset by Watchdog or not. However SoM Colibri iMX7 is a special case due to its design and an errata (e10574) in the SOC.
To differentiate if the SoM was reset by usual Power Cycle or Watchdog, user should readout the register 0xAh of PMIC by the following commands in U-Boot:
# i2c dev 0
# i2c md 33 0a 1
The different values of this register shows the different states of the module:
000a: 00 >> Power ON / Cold Start / Power Cycle
000a: 10 >> Soft Reset/Reboot
000a: 20 >> Reset by Watchdog
The description of the register is also explained in the following image.
Software support
This section has information about generic watchdog support on Linux.
Watchdog interface standartization
Watchdog devices should be accessed via device nodes prefixed with the module family name.
Module Family | Watchdog |
---|---|
Colibri | colibri-watchdog |
Apalis | apalis-watchdog |
Verdin | verdin-watchdog |
Colibri modules
For Colibri module family:
# ls -la /dev/colibri-watchdog
lrwxrwxrwx 1 root root 8 Jun 22 19:53 /dev/colibri-watchdog -> watchdog
It will display the available Colibri watchdog interface and display the name used by the BSP. The corresponding name is important because the Linux kernel logs will print the real device name (in this case, watchdog
), not the symlink (e.g. /dev/colibri-watchdog
).
Apalis modules
For Apalis module family:
# ls -la /dev/apalis-watchdog
lrwxrwxrwx 1 root root 8 Jun 22 19:53 /dev/apalis-watchdog -> watchdog
It will display the available Apalis watchdog interface and display the name used by the BSP. The corresponding name is important because the Linux kernel logs will print the real device name (in this case, watchdog
), not the symlink (e.g. /dev/apalis-watchdog
).
Verdin modules
For Verdin module family:
# ls -la /dev/verdin-watchdog
lrwxrwxrwx 1 root root 8 Jun 22 19:53 /dev/verdin-watchdog -> watchdog
It will display the available Verdin watchdog interface and display the name used by the BSP. The corresponding name is important because the Linux kernel logs will print the real device name (in this case, watchdog
), not the symlink (e.g. /dev/verdin-watchdog
).
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