watchdog之喂狗分析

Watchdog

Watchdog启动之后,系统会在一定时间间隔后重启,这样可以防止系统在遇到死机或者突然崩溃时无法继续运行。若系统死机或者突然崩溃,在一定时间过后,Watchdog会重启系统,使系统恢复运行。

在正常的系统运行过程中,Watchdog若一直不断重启系统,会严重影响到系统的正常工作,因此需要一个程序在后台喂狗,防止系统重启,这样watchdog只有在系统崩溃,喂狗程序无法正常工作的时候重启系统。

Watchdog超时之后,会发送一个内部系统重启信号WDOG_RESET_B_DEB,给SRC(System RestController)。

Watchdog的功能:

1、Timeout event:用户可以设定timeout的时间,通过写Watchdog Control Register的WT(watchdog timeoutfield),设定timeout。当Watchdog enable 之后,watchdog 会读取WT中的timeout时间,counter开始倒计时,当counter为0时,会发送WDOG_RESET_B_DEB,使watchdog重启。

当timeout被设定之后,在counter为0之前,可以通过reload the counter,来重置counter的计时器时间。reload the counter的方法是向watchdog service register(WDOG_WSR)中先写入值0x5555,然后写入值0xAAAA(这两个值必须连续写入,必须先写入0x5555,否则counter是不会被reload的,watchdog 也会在counter计时为0时重启系统)。(寄存器地址以及功能可在spec中查到)。

后台喂狗程序就是通过不断reload counter来实现的。

2、Interrupt event:watchdog 可以产生一个irq,当timeout快发生的时候,IRQ的产生时间可以通过读写WDOG_WICR来控制。

一段简单的喂狗代码:

while(1) {
                        ret = ioctl(fd, WDIOC_KEEPALIVE, 0);//通过ioctl来与dirver进行通信
                        if (ret != 0) {
                                printf("Feed watchdog failed. \n");
                                close(fd);
                                return -1;
                        } else {
                                printf("Feed watchdog every %d seconds.\n", sleep_time);
                        }
                        sleep(sleep_time);//sleep_time 是喂狗的时间间隔
代码通过ioctl来传递参数给底层的driver,下面看一下WDIOC_KEEPALIVE在driver中的代表的操作:

case WDIOC_KEEPALIVE:
		if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
			return -EOPNOTSUPP;
		watchdog_ping(wdd);//wdd is watchdog device 
在这个case语句中会执行watchdog_ping().这个函数就是执行reload counter的操作的,下面是源代码:

static int watchdog_ping(struct watchdog_device *wddev)
{
	int err = 0;

	mutex_lock(&wddev->lock);

	if (test_bit(WDOG_UNREGISTERED, &wddev->status)) {
		err = -ENODEV;
		goto out_ping;
	}

	if (!watchdog_active(wddev))
		goto out_ping;

	if (wddev->ops->ping)		//若dev中有定义ping的ops则pingwatchdog
		err = wddev->ops->ping(wddev);  /* ping the watchdog */
	else
		err = wddev->ops->start(wddev); /* restart watchdog */
out_ping:
	mutex_unlock(&wddev->lock);
	return err;
}
上述代码中:若在驱动中的ops实现了ping函数的功能,则执行ops中的ping函数。

进入到driver看ops中定义的ping函数:

static const struct watchdog_ops wdt_ops = {
	.owner = THIS_MODULE,
	.start = wdt_start,
	.stop = wdt_stop,
	.ping = wdt_ping,
	.set_timeout = wdt_set_timeout,
	.set_pretimeout = wdt_set_pretimeout,
};
ping的函数为wdt_ping();查看wdt_ping()函数:

static int wdt_ping(struct watchdog_device *wdog)
{
	struct wdt_device *wdev = watchdog_get_drvdata(wdog);
	regmap_write(wdev->regmap, WDT_WSR, WDT_SEQ1);
	regmap_write(wdev->regmap, WDT_WSR, WDT_SEQ2);
	return 0;
}

代码中WDT_SEQ1宏定义为0x5555,WDT_SEQ2宏定义为0xAAAA

函数中通过先后连续向寄存器中写0x5555和0xAAAA,来reload counter,阻止watchdog发生timeout事件





你可能感兴趣的:(linux,watchdog,驱动)