Watchdog使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 04/21/2023

    1. 概述

    Watchdog即硬件看门狗,它提供超时复位系统的功能,其功能由定时器和复位功能组成,用户可以设定一个超时时间,并在超时时间以内对它进行“喂狗”的操作,重置其内部计数,如果其内部计算达到了设定的超时时间,就会对系统进行复位重启系统。

    本文中的“WDT”、“看门狗”、“Watchdog”皆为概述中提到的本功能。

    2. 关键字说明

    • watchdog

      看门狗,是一个定时器电路,一般有一个输入,叫喂狗(kicking the dog/service the dog),一个输出到MCU的RST端,MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,给 WDT清零,如果超过规定的时间不喂狗(一般在程序跑飞时),WDT定时超过,就会给出一个复位信号到MCU,使MCU复位。防止MCU死机. 看门狗的作用就是防止程序发生死循环,或者说程序跑飞。

    • watchdog timeout

      看门狗的超时时长,如果超过这个时长不喂狗,WDT定时超过,就会给出一个复位信号到MCU,使MCU复位。

    • watchdog pretimeout

      看门狗的预超时时长。pretimeout是触发时间到系统重启时间点的长度。比如,如果你设置timeout为60, pretimeout为50,那么在50秒的时候(重启之前的 10秒)将触发机关。

    3. 功能描述

    linux 内核支持基于 hrtimer 的 softdog 和基于硬件的硬件看门狗,创建 /dev/watchdog* 设备文件与用户空间程序进行交互。用户空间的 watchdog 程序,会通过/dev/watchdog* 设备进行周期性喂狗。

    图1-1 watchdog框架

    4. 硬件连接介绍

    NA

    5. Uboot用法介绍

    5.1. uboot config配置

    Watchdog 驱动相关的 CONFIG 配置如下:

    (1) CONFIG_SSTAR_WDT:

    [*] SigmaStar drivers  --->
    [*]   Sigmastar watchdog
    

    (2) CONFIG_WATCHDOG_AUTOSTART和CONFIG_WATCHDOG_TIMEOUT_MSECS:

    [*] Device Drivers  --->
    [*]   Watchdog Timer Support --->
    [*]     Automatically start watchdog timer
    [*]     Watchdog timeout in msec
    
    • CONFIG_WATCHDOG_AUTOSTART=Y则uboot启动的时候以WATCHDOG_TIMEOUT_MSECS为超时时间启动watchdog

    • CONFIG_WATCHDOG_TIMEOUT_MSECS默认值为2000,也就是2s

    (3) CONFIG_WATCHDOG:

    [*] Device Drivers  --->
    [*]   Watchdog Timer Support --->
    [*]       Enable U-Boot watchdog reset
    
    • 开启这个宏,uboot每隔一秒喂一次狗

    • 如果开启了CONFIG_WATCHDOG_AUTOSTART但是不开启CONFIG_WATCHDOG,系统在WATCHDOG_TIMEOUT_MSECS ms后将重启

    5.2. Dts配置

    Watchdog 驱动相关的 DTS 配置如下:

    watchdog: watchdog {
        compatible = "sstar,wdt";
        reg = <0x1F006000 0x40>;
        status = "okay";
    };
    

    watchdog DTS配置说明:

    属性 描述 设定值 备注
    compatible 匹配驱动进行驱动注册 "sstar,wdt" 禁止修改
    reg watchdog寄存器信息 硬件设计决定 禁止修改
    status 选择是否使能watchdog驱动 "ok" or "disable" 可根据需要修改

    5.3. Uboot cmd参数说明

    1. 列出可用的watchdog:

      wdt list - list watchdog devices
      
      参数名称 描述
      NA NA
    2. 获取/设置当前watchdog设备:

      wdt dev [<name>] - get/set current watchdog device
      
      参数名称 描述
      name 不带参数时为获取当前操作的 watchdog 设备名称
    3. 启动watchdog:

      wdt start <timeout ms> [flags] - start watchdog timer
      
      参数名称 描述
      timeout ms 指定 watchdog 的超时时间,单位为毫秒
      flags 传递给 watchdog 驱动的 flags 信息,当前驱动未使用该参数
    4. 停止watchdog:

      wdt stop - stop watchdog timer
      
      参数名称 描述
      NA NA
    5. 复位 watchdog 计时:

      wdt reset - reset watchdog timer
      
      参数名称 描述
      NA NA
    6. 立刻触发 watchdog 超时:

      wdt expire [flags] - expire watchdog timer immediately
      
      参数名称 描述
      flag NA

      wdt expire命令的作用为立刻触发watchdog超时,U-Boot原生的实现为将超时设置为1ms,当前硬件不支持此命令。

    5.4. Uboot cmd 使用实例

    wdt list →  wdt list                //
    
    wdt dev [<name>] → wdt dev watchdog // 使用名字为watchdog这个watchdog
    
    wdt start <timeout ms> [flags] → wdt start 10000 //设置watchdog超时时间为10s
    
    wdt reset → wdt reset //在watchdog未超时前,复位watchdog计时
    
    wdt stop → wdt stop // 在watchdog未超时前,停止watchdog
    

    使用这个功能进行测试时需要先关闭CONFIG_WATCHDOG 和CONFIG_WATCHDOG_AUTOSTART,否则uboot系统每隔一段时间会自动ping一次watchdog,你无法测试wdt start功能。

    6. Kernel用法介绍

    6.1. CONFIG 配置

    Watchdog 驱动相关的 CONFIG 配置如下:

        Device Drivers  --->
        [*] SStar SoC platform drivers  --->
        <*>   watchdog driver
    

    6.2. DTS 配置

    Watchdog 驱动相关的 DTS 配置如下:

        WDT: watchdog {
            compatible = "sstar,wdt";
            reg = <0x0 0x1F006000 0x0 0x40>;
            interrupts = <GIC_SPI INT_FIQ_WDT IRQ_TYPE_LEVEL_HIGH>;
            max-length = <40>;
            status = "okay";
        };
    

    watchdog DTS配置说明:

    属性 描述 设定值 备注
    compatible 匹配驱动进行驱动注册 "sstar,wdt" 禁止修改
    reg 设定寄存器bank地址 硬件设计决定 禁止修改
    interrupts 指定 Watchdog 使用的硬件中断号 硬件设计决定 禁止修改
    max-length watchdog计数宽带 硬件设计决定 禁止修改
    status 选择是否使能Watchdog驱动 "ok" or "disable" 可根据需要修改

    6.3. Padmux配置

    NA

    6.4. 模块使用介绍

    6.4.1. SYSFS 使用方法

    NA

    6.4.2. ioctl使用方法

    头文件include/uapi/linux/watchdog.h,struct watchdog_info结构体是对描述了看门狗设备的信息

    • WDIOC_GETSUPPORT:获取看门狗支持哪些功能

    • WDIOC_SETOPTIONS:用于开启或关闭看门狗

    • WDIOC_KEEPALIVE:喂狗操作

    • WDIOC_SETTIMEOUT:设置看门狗超时时间

    • WDIOC_GETPRETIMEOUT:获取看门狗超时时间

    #ifndef _UAPI_LINUX_WATCHDOG_H
    #define _UAPI_LINUX_WATCHDOG_H
    
    #include <linux/ioctl.h>
    #include <linux/types.h>
    
    #define WATCHDOG_IOCTL_BASE 'W'
    
    struct watchdog_info {
        __u32 options;      /* Options the card/driver supports */
        __u32 firmware_version; /* Firmware version of the card */
        __u8  identity[32]; /* Identity of the board */
    };
    
    #define WDIOC_GETSUPPORT    _IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
    #define WDIOC_GETSTATUS     _IOR(WATCHDOG_IOCTL_BASE, 1, int)
    #define WDIOC_GETBOOTSTATUS _IOR(WATCHDOG_IOCTL_BASE, 2, int)
    #define WDIOC_GETTEMP       _IOR(WATCHDOG_IOCTL_BASE, 3, int)
    #define WDIOC_SETOPTIONS    _IOR(WATCHDOG_IOCTL_BASE, 4, int)
    #define WDIOC_KEEPALIVE     _IOR(WATCHDOG_IOCTL_BASE, 5, int)
    #define WDIOC_SETTIMEOUT    _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
    #define WDIOC_GETTIMEOUT    _IOR(WATCHDOG_IOCTL_BASE, 7, int)
    #define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
    #define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
    #define WDIOC_GETTIMELEFT   _IOR(WATCHDOG_IOCTL_BASE, 10, int)
    
    #define WDIOF_UNKNOWN       -1  /* Unknown flag error */
    #define WDIOS_UNKNOWN       -1  /* Unknown status error */
    
    #define WDIOF_OVERHEAT      0x0001  /* Reset due to CPU overheat */
    #define WDIOF_FANFAULT      0x0002  /* Fan failed */
    #define WDIOF_EXTERN1       0x0004  /* External relay 1 */
    #define WDIOF_EXTERN2       0x0008  /* External relay 2 */
    #define WDIOF_POWERUNDER    0x0010  /* Power bad/power fault */
    #define WDIOF_CARDRESET     0x0020  /* Card previously reset the CPU */
    #define WDIOF_POWEROVER     0x0040  /* Power over voltage */
    #define WDIOF_SETTIMEOUT    0x0080  /* Set timeout (in seconds) */
    #define WDIOF_MAGICCLOSE    0x0100  /* Supports magic close char */
    #define WDIOF_PRETIMEOUT    0x0200  /* Pretimeout (in seconds), get/set */
    #define WDIOF_ALARMONLY     0x0400  /* Watchdog triggers a management or
                        other external alarm not a reboot */
    #define WDIOF_KEEPALIVEPING 0x8000  /* Keep alive ping reply */
    
    #define WDIOS_DISABLECARD   0x0001  /* Turn off the watchdog timer */
    #define WDIOS_ENABLECARD    0x0002  /* Turn on the watchdog timer */
    #define WDIOS_TEMPPANIC     0x0004  /* Kernel panic on temperature trip */
    
    #endif /* _UAPI_LINUX_WATCHDOG_H */
    

    6.5. SampleCode

    6.5.1. 启动看门狗

    打开/dev/watchdog设备,watchdog将被启动。

    参考代码如下:

    int wdt_fd = -1;
    wdt_fd = open("/dev/watchdog", O_WRONLY);
    if (wdt_fd == -1)
    {
        // fail to open watchdog device
    }
    

    6.5.2. 关闭看门狗

    参考代码如下:

    int option = WDIOS_DISABLECARD;
    ioctl(wdt_fd, WDIOC_SETOPTIONS, &option);
    if (wdt_fd != -1)
    {
        close(wdt_fd);
        wdt_fd = -1;
    }
    

    6.5.3. 设定超时

    通过标准的IOCTL命令WDIOC_SETTIMEOUT以秒为单位来设定超时,超时时间建议大于5s,参考代码如下:

    #define WATCHDOG_IOCTL_BASE    'W'
    #define WDIOC_SETTIMEOUT       _IOWR(WATCHDOG_IOCTL_BASE, 6, int)
    int timeout = 20;
    ioctl(wdt_fd, WDIOC_SETTIMEOUT, &timeout);
    

    6.5.4. 喂狗

    通过标准的IOCTL命令WDIOC_KEEPALIVE来喂狗,喂狗的间隔应该比超时时间小,参考代码如下:

    #define WATCHDOG_IOCTL_BASE    'W'
    #define WDIOC_KEEPALIVE        _IOR(WATCHDOG_IOCTL_BASE, 5, int)
    ioctl(wdt_fd, WDIOC_KEEPALIVE, 0);
    

    6.5.5. demo

    #include <stdio.h>
    #include <iwatchdog.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/ioctl.h>
    #include <linux/watchdog.h>
    
    int main() {
        int fd = open("/dev/watchdog", O_WRONLY);
        if (fd < 0) {
            perror("Failed to open /dev/watchdog");
            return -1;
        }
        if (ioctl(fd, WDIOC_SETOPTIONS, WDIOS_ENABLECARD) < 0) {
            perror("Failed to enable watchdog");
            close(fd);
            return -1;
        }
        while (1) {
            if (write(fd, "V", 1) != 1) {  // Reset watchdog timer
                perror("Failed to reset watchdog timer");
                break;
            }
            sleep(1);  // Sleep for a while before resetting again
        }
        close(fd);
        return 0;
    }
    

    6.5.6 测试用例

    Linux的测试demo:<Kernel>drivers/sstar/watchdog/ut/wdt_ut.c

    Example:
      # wdt_ut start 10   /* 启动watchdog后,系统会不断去喂狗,所以10秒后系统不会重启 */
      # wdt_ut reset 10   /* 启动watchdog后,系统不会去喂狗,所以10秒后系统将重启 */
    

    7. API参考

    NA

    8. FAQ

    NA