参考博文: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;
}
具体的实现细节,以后有时间再来分析。