Linux启动过程初始化(十二)----watchdog初始化

本文深入解析Linux系统下Watchdog的工作原理及其实现机制,详细介绍了内核模块与用户空间程序如何通过/dev/watchdog设备交互,确保系统稳定运行,防止因核心进程崩溃导致的系统停摆。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考博文:https://blog.youkuaiyun.com/huashibuliao/article/details/78281656
首先了解一下Linux系统下的watchdog的用法
Linux 自带了一个 watchdog 的实现,用于监视系统的运行,包括一个内核 watchdog module 和一个用户空间的 watchdog 程序。内核 watchdog 模块通过 /dev/watchdog 这个字符设备与用户空间通信。用户空间程序一旦打开 /dev/watchdog 设备(俗称“开门放狗”),就会导致在内核中启动一个1分钟的定时器(系统默认时间),此后,用户空间程序需要保证在1分钟之内向这个设备写入数据(俗称“定期喂狗”),每次写操作会导致重新设定定时器。如果用户空间程序在1分钟之内没有写操作,定时器到期会导致一次系统重启。通过这种机制,我们可以保证系统核心进程大部分时间都处于运行状态,即使特定情形下进程崩溃,因无法正常定时“喂狗”,Linux系统在看门狗作用下重新启动(reboot),核心进程又运行起来了。
在Linux3.3下,针对定时器看门狗进行分析:
通过system.map追踪到与watchdog相关的初始化函数如下:

c02f5078 t wdt_service
c02f50e0 t davinci_wdt_release
c02f511c t davinci_wdt_write
c02f513c t davinci_wdt_open
c02f5234 t davinci_wdt_ioctl
c0418134 t davinci_wdt_probe
c041928c t davinci_wdt_remove
c044c3a0 r davinci_wdt_fops
c0585edc t platform_wdt_driver_init
c058e6cc t platform_wdt_driver_exit
c0599fa8 t __initcall_platform_wdt_driver_init6
c05a46a8 D da8xx_wdt_device
c05c328c d platform_wdt_driver
c05c32e0 d davinci_wdt_miscdev
c05e9ecc B wdt_clk
c05e9ed0 b wdt_mem
c05e9ed4 b wdt_base
c05e9ed8 b wdt_status

在sourceinsight中搜索工程,可以在Davinci_wdt.c (drivers\watchdog)中找到如下的函数:

wdt_service
davinci_wdt_release
davinci_wdt_write
davinci_wdt_open
davinci_wdt_ioctl
davinci_wdt_probe
davinci_wdt_remove
davinci_wdt_fops

在Davinci_wdt.c的结尾,有这样的定义:

module_platform_driver(platform_wdt_driver);

module_platform_driver在Platform_device.h (include\linux)中的定义如下:


/* module_platform_driver() - Helper macro for drivers that don't do
 * anything special in module init/exit.  This eliminates a lot of
 * boilerplate.  Each module may only use this macro once, and
 * calling it replaces module_init() and module_exit()
 */
#define module_platform_driver(__platform_driver) \
	module_driver(__platform_driver, platform_driver_register, \
			platform_driver_unregister)

展开后:

#define module_platform_driver(platform_wdt_driver)
   module_driver(platform_wdt_driver, platform_driver_register, \
			platform_driver_unregister)	

module_driver在Device.h (include\linux) 中的定义如下:


/**
 * module_driver() -这个宏用于驱动在module init/exit 阶段没有特别操作的时候. 它减少了很多的样板代
 * 码,每个模块仅可以使用这个宏一次,并且通过调用它来替代module init()和module exit()。
 *
 * @__driver: driver name
 * @__register: register function for this driver type
 * @__unregister: unregister function for this driver type
 *
 * Use this macro to construct bus specific macros for registering
 * drivers, and do not use it on its own.
 */
#define module_driver(__driver, __register, __unregister) \
static int __init __driver##_init(void) \
{ \
	return __register(&(__driver)); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
	__unregister(&(__driver)); \
} \
module_exit(__driver##_exit);

将module_driver(platform_wdt_driver, platform_driver_register,
platform_driver_unregister) 展开后,内容如下:

static int __init    platform_wdt_driver_init(void) 
{ 
	return platform_driver_register(&(platform_wdt_driver)); 
} 
module_init(platform_wdt_driver_init); \


static void __exit   platform_wdt_driver_exit(void) \
{ \
	platform_driver_unregister(&(platform_wdt_driver)); \
} \
module_exit(platform_wdt_driver_exit);

platform_wdt_driver的结构体如下:


static struct platform_driver platform_wdt_driver = {
	.driver = {
		.name = "watchdog",
		.owner	= THIS_MODULE,
	},
	.probe = davinci_wdt_probe,
	.remove = __devexit_p(davinci_wdt_remove),
};

platform_driver的结构体内容如下:


struct platform_driver {
	int (*probe)(struct platform_device *);
	int (*remove)(struct platform_device *);
	void (*shutdown)(struct platform_device *);
	int (*suspend)(struct platform_device *, pm_message_t state);
	int (*resume)(struct platform_device *);
	struct device_driver driver;
	const struct platform_device_id *id_table;
};

platform_driver_register函数位于Platform.c (drivers\base):


/**
 * platform_driver_register - register a driver for platform-level devices
 * @drv: platform driver structure
 */
int platform_driver_register(struct platform_driver *drv)
{
	drv->driver.bus = &platform_bus_type;
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

以上是将看门狗驱动注册到platform总线上,接下来再看一下platform设备注册:
看门狗platform设备注册发生在:Board-da850-evm.c (arch\arm\mach-davinci)
->
ret = da8xx_register_watchdog();

int __init da8xx_register_watchdog(void)
{
	return platform_device_register(&da8xx_wdt_device);
}

->


/**
 * platform_device_register - add a platform-level device
 * @pdev: platform device we're adding
 */
int platform_device_register(struct platform_device *pdev)
{
	device_initialize(&pdev->dev);
	arch_setup_pdev_archdata(pdev);
	return platform_device_add(pdev);
}

da8xx_wdt_device设备结构体的内容如下:


struct platform_device da8xx_wdt_device = {
	.name		= "watchdog",
	.id		= -1,
	.num_resources	= ARRAY_SIZE(da8xx_watchdog_resources),
	.resource	= da8xx_watchdog_resources,
};

看门狗平台设备和平台驱动注册完之后,platform_wdt_driver会通过驱动名称“"DaVinci Watchdog”与对应的平台设备匹配,成功将调用davinci_wdt_probe探测函数。


static int __devinit davinci_wdt_probe(struct platform_device *pdev)
{
	int ret = 0, size;
	struct device *dev = &pdev->dev;

	wdt_clk = clk_get(dev, NULL);
	if (WARN_ON(IS_ERR(wdt_clk)))
		return PTR_ERR(wdt_clk);

	clk_enable(wdt_clk);

	if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
		heartbeat = DEFAULT_HEARTBEAT;

	dev_info(dev, "heartbeat %d sec\n", heartbeat);

	wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (wdt_mem == NULL) {
		dev_err(dev, "failed to get memory region resource\n");
		return -ENOENT;
	}

	size = resource_size(wdt_mem);
	if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
		dev_err(dev, "failed to get memory region\n");
		return -ENOENT;
	}

	wdt_base = ioremap(wdt_mem->start, size);
	if (!wdt_base) {
		dev_err(dev, "failed to map memory region\n");
		release_mem_region(wdt_mem->start, size);
		wdt_mem = NULL;
		return -ENOMEM;
	}

	ret = misc_register(&davinci_wdt_miscdev);
	if (ret < 0) {
		dev_err(dev, "cannot register misc device\n");
		release_mem_region(wdt_mem->start, size);
		wdt_mem = NULL;
	} else {
		set_bit(WDT_DEVICE_INITED, &wdt_status);
	}

	iounmap(wdt_base);
	return ret;
}

具体的实现细节,以后有时间再来分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值