Linux内核4.14版本——watchdog看门狗框架分析

目录

0 简介

1. 设备的注册

1.1 dw_wdt_drv_probe

1.2 watchdog_register_device

1.3 __watchdog_register_device

1.4 最终misc_register注册watchdog_miscdev

2. watchdog_miscdev设备分析

2.1 watchdog_open

2.2 watchdog_write

2.3 watchdog_release

2.4 watchdog_stop

2.5 watchdog_set_timeout

2.6 watchdog_ping

2.7 watchdog_ioctl

3. 使用标准的内核框架wdt driver时,需要特别注意以下两点

3.1 NOWAYOUT(无路可逃)的使用

3.2 magic close特性

4. 应用层代码(app demo)


0 简介

版本:Linux 4.14
用到的文件:
kernel\watchdog.c
drivers\watchdog\dw_wdt.c
drivers\watchdog\watchdog_dev.c
drivers\watchdog\watchdog_core.c

      wdt的驱动挺特别的,linux内核中也对它做了一个封装并归纳处理总结出了一个框架,分为以下三层:统一driver层(watchdog_dev),核心层(watchdog_core),具体的设备层(本文以dw wdt为例)。
      在写wdt的时候会发现,和其他driver不同的是,不需要我们在自己的driver中去创建节点,我们只需要实现ops结构体成员即可,然后去调用wdt核心层的api注册ops即可。
      其实,创建节点的工作在wdt的统一driver层已经实现了,这是因wdt设备在各个soc上是一个高度统一的设备,可以被高度抽象出来,查看代码watchdog_dev.c中就可以看到,这是一个标准的字符设备驱动,该文件中创建”dev/watchdog”节点,同时向上层提供了ioctl接口。
       driver中的各个接口调用都是以函数指针的方式去调用,而这些函数指针在我们每个soc自己的巨头的wdt driver层去初始化然后注册。

1. 设备的注册

1.1 dw_wdt_drv_probe

drivers\watchdog\dw_wdt.c

#ifdef CONFIG_OF
static const struct of_device_id dw_wdt_of_match[] = {
    { .compatible = "snps,dw-wdt", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw_wdt_of_match);
#endif

static struct platform_driver dw_wdt_driver = {
    .probe        = dw_wdt_drv_probe,
    .remove        = dw_wdt_drv_remove,
    .driver        = {
        .name    = "dw_wdt",
        .of_match_table = of_match_ptr(dw_wdt_of_match),
        .pm    = &dw_wdt_pm_ops,
    },
};

      设备树中比较compatible = "snps,dw-wdt",比较通过后调用dw_wdt_drv_probe函数。

static int dw_wdt_drv_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct watchdog_device *wdd;
    struct dw_wdt *dw_wdt;
    struct resource *mem;
    int ret;

    dw_wdt = devm_kzalloc(dev, sizeof(*dw_wdt), GFP_KERNEL);
    if (!dw_wdt)
        return -ENOMEM;

    wdd->info = &dw_wdt_ident;
    wdd->ops = &dw_wdt_ops;  //设置操作函数
    ........
    
    watchdog_set_nowayout(wdd, nowayout);
    
    ........

    platform_set_drvdata(pdev, dw_wdt);

    watchdog_set_restart_priority(wdd, 128);

    ret = watchdog_register_device(wdd);
    if (ret)
        goto out_disable_clk;

    return 0;

out_disable_clk:
    clk_disable_unprepare(dw_wdt->clk);
    return ret;
}

static const struct watchdog_ops dw_wdt_ops = {
    .owner        = THIS_MODULE,
    .start        = dw_wdt_start,
    .stop        = dw_wdt_stop,
    .ping        = dw_wdt_ping,
    .set_timeout    = dw_wdt_set_timeout,
    .get_timeleft    = dw_wdt_get_timeleft,
    .restart    = dw_wdt_restart,
};

      前面一些关于硬件、IO等的设置,这里不做介绍,注意wdt的fops就行。我们主要讲watchdog_register_device函数。

1.2 watchdog_register_device

      该函数drivers\watchdog\watchdog_core.c在这里面,如下:

int watchdog_register_device(struct watchdog_device *wdd)
{
    int ret;

    mutex_lock(&wtd_deferred_reg_mutex);
    if (wtd_deferred_reg_done)
        ret = __watchdog_register_device(wdd);
    else
        ret = watchdog_deferred_registration_add(wdd);
    mutex_unlock(&wtd_deferred_reg_mutex);
    return ret;
}

      wtd_deferred_reg_done全局变量已经定义了,所以走__watchdog_register_device分支。

static int __init watchdog_deferred_registration(void)
{
    mutex_lock(&wtd_deferred_reg_mutex);
    wtd_deferred_reg_done = true;
    while (!list_empty(&wtd_deferred_reg_list)) {
        struct watchdog_device *wdd;

        wdd = list_first_entry(&wtd_deferred_reg_list,
                       struct watchdog_device, deferred);
        list_del(&wdd->deferred);
        __watchdog_register_device(wdd);
    }
    mutex_unlock(&wtd_deferred_reg_mutex);
    return 0;
}

static int __init watchdog_init(void)
{
    int err;

    err = watchdog_dev_init();
    if (err < 0)
        return err;

    watchdog_deferred_registration();
    return 0;
}

subsys_initcall_sync(watchdog_init);

1.3 __watchdog_register_device

static int __watchdog_register_device(struct watchdog_device *wdd)
{
    int ret, id = -1;
    .......
    
    ret = watchdog_dev_register(wdd);

    ....

    return 0;
}

      其他不管,发现调用watchdog_dev_register。

1.4 最终misc_register注册watchdog_miscdev

static int watchdog_cdev_register(struct watchdog_device *wdd)
{
    struct watchdog_core_data *wd_data;
    int err;

    ......

    if (wdd->id == 0) {
        old_wd_data = wd_data;
        watchdog_miscdev.parent = wdd->parent;
        err = misc_register(&watchdog_miscdev);
        if (err != 0) {
            pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
                wdd->info->identity, WATCHDOG_MINOR, err);
            if (err == -EBUSY)
                pr_err("%s: a legacy watchdog module is probably present.\n",
                    wdd->info->identity);
            old_wd_data = NULL;
            kfree(wd_data);
            return err;
        }
    }

    .......
    return 0;
}

      发现最终注册了一个混杂设备watchdog_miscdev,其定义如下。

static const struct file_operations watchdog_fops = {
    .owner        = THIS_MODULE,
    .write        = watchdog_write,
    .unlocked_ioctl    = watchdog_ioctl,
    .open        = watchdog_open,
    .release    = watchdog_release,
};

static struct miscdevice watchdog_miscdev = {
    .minor        = WATCHDOG_MINOR,
    .name        = "watchdog",
    .fops        = &watchdog_fops,
};

2. watchdog_miscdev设备分析

2.1 watchdog_open

/*
 *    watchdog_open: open the /dev/watchdog* devices.
 *    @inode: inode of device
 *    @file: file handle to device
 *
 *    When the /dev/watchdog* device gets opened, we start the watchdog.
 *    Watch out: the /dev/watchdog device is single open, so we make sure
 *    it can only be opened once.
 */
static int watchdog_open(struct inode *inode, struct file *file)
{
    struct watchdog_core_data *wd_data;
    struct watchdog_device *wdd;
    bool hw_running;
    int err;

    ......

    err = watchdog_start(wdd);
    if (err < 0)
        goto out_mod;

    ......
}

      当打开open("/dev/watchdog")时,最终调用watchdog_open,可以看出最终调用了watchdog_start。

/*
 *    watchdog_start: wrapper to start the watchdog.
 *    @wdd: the watchdog device to start
 *
 *    The caller must hold wd_data->lock.
 *
 *    Start the watchdog if it is not active and mark it active.
 *    This function returns zero on success or a negative errno code for
 *    failure.
 */

static int watchdog_start(struct watchdog_device *wdd)
{
    struct watchdog_core_data *wd_data = wdd->wd_data;
    unsigned long started_at;
    int err;

    .....
    set_bit(_WDOG_KEEPALIVE, &wd_data->status);

    started_at = jiffies;
    if (watchdog_hw_running(wdd) && wdd->ops->ping)
        err = wdd->ops->ping(wdd);
    else
        err = wdd->ops->start(wdd);
    .....

    return err;
}

      查看watchdog_start源码可知,最终调用了wdt fops中的start函数。

2.2 watchdog_write

/*
 *    watchdog_write: writes to the watchdog.
 *    @file: file from VFS
 *    @data: user address of data
 *    @len: length of data
 *    @ppos: pointer to the file offset
 *
 *    A write to a watchdog device is defined as a keepalive ping.
 *    Writing the magic 'V' sequence allows the next close to turn
 *    off the watchdog (if 'nowayout' is not set).
 */

static ssize_t watchdog_write(struct file *file, const char __user *data,
                        size_t len, loff_t *ppos)
{
    struct watchdog_core_data *wd_data = file->private_data;
    struct watchdog_device *wdd;
    int err;
    size_t i;
    char c;

    if (len == 0)
        return 0;

    /*
     * Note: just in case someone wrote the magic character
     * five months ago...
     */
    clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);

    /* scan to see whether or not we got the magic character */
    for (i = 0; i != len; i++) {
        if (get_user(c, data + i))
            return -EFAULT;
        if (c == 'V')
            set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status);
    }

    /* someone wrote to us, so we send the watchdog a keepalive ping */

    err = -ENODEV;
    mutex_lock(&wd_data->lock);
    wdd = wd_data->wdd;
    if (wdd)
        err = watchdog_ping(wdd);
    mutex_unlock(&wd_data->lock);

    if (err < 0)
        return err;

    return len;
}

      这里的写有一个特殊操作,如果向wdt节点写“V”字符时,则会置位标志为_WDOG_ALLOW_RELEASE,即允许release,当上层去close节点的时候会callback到这一层的release接口,release会去判断_WDOG_ALLOW_RELEASE,如果不被置位则不执行watchdog_stop,即虽然上层关掉了fd,但是底层实际没有执行stop的操作。如果被置位,就执行watchdog_stop,按照上面的分析,watchdog_stop又会判断NOWAYOUT是否被置位。即想要关闭wdt,首先需要disable _WDOG_ALLOW_RELEASE,即去掉该选项。即在close节点前向节点写“V”,然后再clsoe,这样才可以正真调用到具体driver的stop接口

2.3 watchdog_release

/*
 *    watchdog_release: release the watchdog device.
 *    @inode: inode of device
 *    @file: file handle to device
 *
 *    This is the code for when /dev/watchdog gets closed. We will only
 *    stop the watchdog when we have received the magic char (and nowayout
 *    was not set), else the watchdog will keep running.
 */

static int watchdog_release(struct inode *inode, struct file *file)
{
    struct watchdog_core_data *wd_data = file->private_data;
    struct watchdog_device *wdd;
    int err = -EBUSY;
    bool running;
    ......

    /*
     * We only stop the watchdog if we received the magic character
     * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
     * watchdog_stop will fail.
     */
    if (!test_bit(WDOG_ACTIVE, &wdd->status))
        err = 0;
    else if (test_and_clear_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) ||
         !(wdd->info->options & WDIOF_MAGICCLOSE))
        err = watchdog_stop(wdd);

    /* If the watchdog was not stopped, send a keepalive ping */
    if (err < 0) {
        pr_crit("watchdog%d: watchdog did not stop!\n", wdd->id);
        watchdog_ping(wdd);
    }

    watchdog_update_worker(wdd);

    /* make sure that /dev/watchdog can be re-opened */
    clear_bit(_WDOG_DEV_OPEN, &wd_data->status);
    ......
    return 0;
}

      release 接口,上层做close的时候会调用到。release会去判断_WDOG_ALLOW_RELEASE,而这个标志在write函数中会被置位,(向节点写“V”操作)。如果不被置位则不执行watchdog_stop即虽然上层关掉了fd,但是底层实际没有执行stop的操作。如果被置位,就执行watchdog_stop,按照上面的分析,watchdog_stop又会判断NOWAYOUT是否被置位。即想要关闭wdt,首先需要disable _WDOG_ALLOW_RELEASE,即去掉该选项。然后在close节点前向节点写“V”,然后再clsoe,这样才可以正真调用到具体driver的stop接口。

2.4 watchdog_stop

/*
 *    watchdog_stop: wrapper to stop the watchdog.
 *    @wdd: the watchdog device to stop
 *
 *    The caller must hold wd_data->lock.
 *
 *    Stop the watchdog if it is still active and unmark it active.
 *    This function returns zero on success or a negative errno code for
 *    failure.
 *    If the 'nowayout' feature was set, the watchdog cannot be stopped.
 */

static int watchdog_stop(struct watchdog_device *wdd)
{
    int err = 0;

    if (!watchdog_active(wdd))
        return 0;

    if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
        pr_info("watchdog%d: nowayout prevents watchdog being stopped!\n",
            wdd->id);
        return -EBUSY;
    }

    if (wdd->ops->stop) {
        clear_bit(WDOG_HW_RUNNING, &wdd->status);
        err = wdd->ops->stop(wdd);
    } else {
        set_bit(WDOG_HW_RUNNING, &wdd->status);
    }

    if (err == 0) {
        clear_bit(WDOG_ACTIVE, &wdd->status);
        watchdog_update_worker(wdd);
    }

    return err;
}

      WDOG_NO_WAY_OUT,这里有个特殊的一点是上层调用进这个接口想关闭wdt即终止计数功能时,这里会判断status是否被设置为WDOG_NO_WAY_OUT状态,如果设置了,则直接返回不去调用实际driver中的stop函数。也就是说当NOWAYOUT被配置后,无论上层是close wdt节点还是调用统一层stop接口,wdt都是不会关掉的,会一直计数下去,如果不持续喂狗就会reset。

static bool nowayout = WATCHDOG_NOWAYOUT;
#define WATCHDOG_NOWAYOUT        IS_BUILTIN(CONFIG_WATCHDOG_NOWAYOUT)
/* Use the following function to set the nowayout feature */
static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout)
{
    if (nowayout)
        set_bit(WDOG_NO_WAY_OUT, &wdd->status);
}

       由上可以看出如果配置了CONFIG_WATCHDOG_NOWAYOUT项,则watchdog_set_nowayout在dw_wdt_drv_probe就会被执行,WDOG_NO_WAY_OUT状态就会被置起来,当上层通过ioctl调用了wdt同一层的stop接口时,则直接返回。

2.5 watchdog_set_timeout

/*
 *    watchdog_set_timeout: set the watchdog timer timeout
 *    @wdd: the watchdog device to set the timeout for
 *    @timeout: timeout to set in seconds
 *
 *    The caller must hold wd_data->lock.
 */

static int watchdog_set_timeout(struct watchdog_device *wdd,
                            unsigned int timeout)
{
    int err = 0;

    if (!(wdd->info->options & WDIOF_SETTIMEOUT))
        return -EOPNOTSUPP;

    if (watchdog_timeout_invalid(wdd, timeout))
        return -EINVAL;

    if (wdd->ops->set_timeout) {
        err = wdd->ops->set_timeout(wdd, timeout);
    } else {
        wdd->timeout = timeout;
        /* Disable pretimeout if it doesn't fit the new timeout */
        if (wdd->pretimeout >= wdd->timeout)
            wdd->pretimeout = 0;
    }

    watchdog_update_worker(wdd);

    return err;
}

      设置超时时间,一般正常喂狗会下发一个时间,如果上层想主动重启,只需设置时间为0,当然实际的底层driver需要对时间做判断,当时间为0时,就重启系统。

2.6 watchdog_ping

/*
 *    watchdog_ping: ping the watchdog.
 *    @wdd: the watchdog device to ping
 *
 *    The caller must hold wd_data->lock.
 *
 *    If the watchdog has no own ping operation then it needs to be
 *    restarted via the start operation. This wrapper function does
 *    exactly that.
 *    We only ping when the watchdog device is running.
 */

static int watchdog_ping(struct watchdog_device *wdd)
{
    struct watchdog_core_data *wd_data = wdd->wd_data;

    if (!watchdog_active(wdd) && !watchdog_hw_running(wdd))
        return 0;

    set_bit(_WDOG_KEEPALIVE, &wd_data->status);

    wd_data->last_keepalive = jiffies;
    return __watchdog_ping(wdd);
}

static int __watchdog_ping(struct watchdog_device *wdd)
{
    struct watchdog_core_data *wd_data = wdd->wd_data;
    unsigned long earliest_keepalive = wd_data->last_hw_keepalive +
                msecs_to_jiffies(wdd->min_hw_heartbeat_ms);
    int err;

    if (time_is_after_jiffies(earliest_keepalive)) {
        mod_delayed_work(watchdog_wq, &wd_data->work,
                 earliest_keepalive - jiffies);
        return 0;
    }

    wd_data->last_hw_keepalive = jiffies;

    if (wdd->ops->ping)
        err = wdd->ops->ping(wdd);  /* ping the watchdog */
    else
        err = wdd->ops->start(wdd); /* restart watchdog */

    watchdog_update_worker(wdd);

    return err;
}

2.7 watchdog_ioctl

/*
 *    watchdog_ioctl: handle the different ioctl's for the watchdog device.
 *    @file: file handle to the device
 *    @cmd: watchdog command
 *    @arg: argument pointer
 *
 *    The watchdog API defines a common set of functions for all watchdogs
 *    according to their available features.
 */

static long watchdog_ioctl(struct file *file, unsigned int cmd,
                            unsigned long arg)
{
    struct watchdog_core_data *wd_data = file->private_data;
    void __user *argp = (void __user *)arg;
    struct watchdog_device *wdd;
    int __user *p = argp;
    unsigned int val;
    int err;

    mutex_lock(&wd_data->lock);

    wdd = wd_data->wdd;
    if (!wdd) {
        err = -ENODEV;
        goto out_ioctl;
    }

    err = watchdog_ioctl_op(wdd, cmd, arg);
    if (err != -ENOIOCTLCMD)
        goto out_ioctl;

    switch (cmd) {
    case WDIOC_GETSUPPORT:
        err = copy_to_user(argp, wdd->info,
            sizeof(struct watchdog_info)) ? -EFAULT : 0;
        break;
    case WDIOC_GETSTATUS:
        val = watchdog_get_status(wdd);
        err = put_user(val, p);
        break;
    case WDIOC_GETBOOTSTATUS:
        err = put_user(wdd->bootstatus, p);
        break;
    case WDIOC_SETOPTIONS:
        if (get_user(val, p)) {
            err = -EFAULT;
            break;
        }
        if (val & WDIOS_DISABLECARD) {
            err = watchdog_stop(wdd);
            if (err < 0)
                break;
        }
        if (val & WDIOS_ENABLECARD)
            err = watchdog_start(wdd);
        break;
    case WDIOC_KEEPALIVE:
        if (!(wdd->info->options & WDIOF_KEEPALIVEPING)) {
            err = -EOPNOTSUPP;
            break;
        }
        err = watchdog_ping(wdd);
        break;
    case WDIOC_SETTIMEOUT:
        if (get_user(val, p)) {
            err = -EFAULT;
            break;
        }
        err = watchdog_set_timeout(wdd, val);
        if (err < 0)
            break;
        /* If the watchdog is active then we send a keepalive ping
         * to make sure that the watchdog keep's running (and if
         * possible that it takes the new timeout) */
        err = watchdog_ping(wdd);
        if (err < 0)
            break;
        /* Fall */
    case WDIOC_GETTIMEOUT:
        /* timeout == 0 means that we don't know the timeout */
        if (wdd->timeout == 0) {
            err = -EOPNOTSUPP;
            break;
        }
        err = put_user(wdd->timeout, p);
        break;
    case WDIOC_GETTIMELEFT:
        err = watchdog_get_timeleft(wdd, &val);
        if (err < 0)
            break;
        err = put_user(val, p);
        break;
    case WDIOC_SETPRETIMEOUT:
        if (get_user(val, p)) {
            err = -EFAULT;
            break;
        }
        err = watchdog_set_pretimeout(wdd, val);
        break;
    case WDIOC_GETPRETIMEOUT:
        err = put_user(wdd->pretimeout, p);
        break;
    default:
        err = -ENOTTY;
        break;
    }

out_ioctl:
    mutex_unlock(&wd_data->lock);
    return err;
}

3. 使用标准的内核框架wdt driver时,需要特别注意以下两点

3.1 NOWAYOUT(无路可逃)的使用

       有的时候我们希望看门狗不被停止,即上层的任何关狗的动作都不予支持,此时就可以使用NOWAYOUT功能,接配置内核的标准配置项:CONFIG_WATCHDOG_NOWAYOUT
使能该项后,要为我们的driver所用需要在具体的wdt driver中对该配置进行支持,即调用watchdog_set_nowayout()去设置WDOG_NO_WAY_OUT:

static bool nowayout = WATCHDOG_NOWAYOUT;
#define WATCHDOG_NOWAYOUT        IS_BUILTIN(CONFIG_WATCHDOG_NOWAYOUT)
/* Use the following function to set the nowayout feature */
static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool nowayout)
{
    if (nowayout)
        set_bit(WDOG_NO_WAY_OUT, &wdd->status);
}

      配置后会去执行set_bit(WDOG_NO_WAY_OUT, &wdd->status);置位WDOG_NO_WAY_OUT。在上层调用统一driver层IOCTL去调用watchdog_stop()时,watchdog_stop会去判断是否WDOG_NO_WAY_OUT被置位,如果设置了,则直接返回不去调用实际driver中的stop函数
这样就可以屏蔽所有关wdt的动作,这个操作仍然在统一设备层,具体的wdt driver不用管这个

3.2 magic close特性

      有的时候我们想停掉狗,不想然他reset,如果系统使用了标准的wdt框架,则需要magic close的支持。

      magic close即向wdt节点写字符“V”向wdt节点写“V”字符时,被调用到的接口watchdog_write()会置位标志为_WDOG_ALLOW_RELEASE。当上层close节点时,会调用标准的wdt统一driver层的release接口,release会去判断_WDOG_ALLOW_RELEASE,如果不被置位则不执行watchdog_stop即虽然上层关掉了fd,但是底层实际没有执行stop的操作。如果被置位,就执行watchdog_stop,按照上面的分析,watchdog_stop又会判断NOWAYOUT是否被置位。
       所以想要关闭wdt rest功能结束其计数,首先需要disable _WDOG_ALLOW_RELEASE,即去掉该选项。然后在close节点前向节点写“V”,然后再clsoe,这样才可以正真调用到具体driver的stop接口。

4. 应用层代码(app demo)

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>
#include <getopt.h>
#include <sys/signal.h>

//watchdog 
#define WATCHDOG_IOCTL_BASE     'W'

struct watchdog_info {
    unsigned int options;          /* Options the card/driver supports */
    unsigned int firmware_version; /* Firmware version of the card */
    char 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_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_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 */

int wdt_fd;
int time_out = 5;
#define DEFAULT_PING_RATE    1
void stop_signal()
{
    int val = 0 , ret = 0 ;

    val = WDIOS_DISABLECARD ;
    ret = ioctl(wdt_fd, WDIOC_SETOPTIONS, &val) ;
    if (ret < 0)
        printf("ioctl WDIOC_GETSUPPORT failed with %d.\n", ret);

    printf("===watchdow will be closed===\n") ;
    close(wdt_fd) ;
    exit(0);
    
}

int main(int argc, char *argv[])
{
    int ret;
    static int count = 0;
    struct watchdog_info wdt_info;
    unsigned int ping_rate = DEFAULT_PING_RATE;

    signal(SIGINT, stop_signal) ;

    wdt_fd = open("/dev/watchdog0", O_RDWR);
    if(wdt_fd < 0)
    {
        printf("open /dev/watchdog0 failed.\n");
    }

    /* get watchdog infomation struct */
    ret = ioctl(wdt_fd, WDIOC_GETSUPPORT, &wdt_info);
    if (ret < 0)
        printf("ioctl WDIOC_GETSUPPORT failed.\n");
    else
    {
        printf("options = 0x%x,id = %s\n", wdt_info.options, wdt_info.identity);
    }

    ioctl(wdt_fd, WDIOC_SETTIMEOUT, &time_out);
    if (ret < 0)
        printf("ioctl WDIOC_SETTIMEOUT failed.\n");
    
    while(1)
    {
        
        if(count > 10)
        {
            printf("unfood watchdog, count = %d \n",count++);
        }
        else
        {
            ioctl(wdt_fd,WDIOC_KEEPALIVE,NULL);
            printf("food watchdog, count = %d \n",count++);
        }
        sleep(DEFAULT_PING_RATE);
    }    

    close(wdt_fd);
    return 0;
}

  • 6
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: s32k的Watchdog看门狗)是一种硬件功能,旨在提高系统的可靠性和稳定性。它是一种定时器,用于监视系统的运行状态,并在系统停止响应时自动重启系统或采取其他措施。 Watchdog的工作原理是在系统启动时启动一个计时器,定时器周期性地向操作系统发送信号,作为系统正常工作的标志。如果系统正常运行,操作系统会在每个周期内重置或刷新Watchdog计时器。如果系统出现故障或停止响应,操作系统将无法刷新Watchdog计时器,计时器则会超时。 一旦Watchdog计时器超时,它将触发一个复位信号,导致系统重启。这样,Watchdog起到了保护系统免受死锁(系统停止响应)和其他故障的作用。此外,Watchdog还可以设置为在系统停止响应时触发其他操作,例如发送警报信号或进行日志记录。 通过使用Watchdog,系统可以在遇到严重故障时及时进行自动重启,从而避免人为干预或系统长时间停机。这对于要求高可靠性和稳定性的系统,如自动控制系统、仪表仪器、工业控制等领域非常重要。 综上所述,s32k的Watchdog是一项重要的功能,它有效地监控系统的运行状态并在必要时采取措施以保护系统的可靠性。 ### 回答2: S32K的看门狗Watchdog)是一种用于监视系统运行状态的重要功能。它类似于现实生活中的看门狗,当系统出现异常或崩溃时,看门狗能够自动重启系统,确保系统持续可靠运行。 看门狗主要由看门狗定时器(WDT)和看门狗控制寄存器(WCR)两部分组成。看门狗定时器是一个独立的硬件计数器,它在系统启动时启动计数,并按照预设时间间隔进行递减。当计数器值归零时,看门狗控制寄存器会触发一个复位信号,使系统重启。这样就能避免系统长时间停滞或假死,提高系统的稳定性和可靠性。 在S32K中,我们可以通过设置寄存器来配置看门狗的工作模式和计数器时间。可以根据系统的需求,设置适当的计数器时间,以及是否启用看门狗复位功能。同时,看门狗还可以配合其他系统监控功能一起工作,例如外部中断或系统时钟监控器。 需要注意的是,看门狗并不是万能的解决方案。在设计中还需慎重考虑计数器时间的设置,以免触发误复位。另外,应及时处理系统异常问题,以避免看门狗频繁触发重启。 总之,S32K的看门狗是一项非常重要的系统保护功能,它能够监控系统运行状态并自动重启系统,确保系统的可靠性和稳定性。合理配置和使用看门狗可以大大提高系统的工作效率和可用性。 ### 回答3: S32K是一款由恩智浦公司开发的32位微控制器,其内置了一种看门狗定时器(Watchdog Timer)。Watchdog Timer是一种硬件设备,在嵌入式系统中用于检测和处理系统可能出现的故障或错误情况。 看门狗的主要工作原理是通过定时器来监视系统的运行状态。它需要被定期重置,否则将会触发一个系统复位信号。这样,如果系统在正常运行时出现问题,导致无法及时重置看门狗,系统将会被强制复位,以防止系统崩溃或陷入无限循环。 S32K微控制器上的看门狗具有以下特点: 1. 看门狗定时器的计数器可以由软件程序进行配置,并且可以在系统的各个阶段进行启用、禁用或重置。 2. 看门狗定时器可以设置一个预置值,定时器计数器必须在该值之前被重置,否则将会触发看门狗复位。 3. 看门狗复位信号可以用来重新启动整个系统,以确保系统从错误状态中恢复。 通过使用S32K的看门狗功能,我们可以增强系统的稳定性和可靠性。当系统出现异常时,看门狗能够及时检测问题,并采取相应措施,例如强制系统重启,确保系统能够正常工作。这种硬件级别的保护机制能够提高系统的可靠性和抗干扰能力,使S32K微控制器在各种应用场景下都能够保持正常运行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值