1 Linux 下硬件 watchdog 工作原理
1.1 功能:
可以在系统出现故障时,自动重新启动系统
1.2 基本工作原理:
启动watchdog进程(open(/dev/watchdog)),如果在某一设定时间间隔内,/dev/watchdog没有被执行write操作,硬件watchdog电路就会重新启动系统。
1.3 硬件原理图
PCLK是系统时钟 ----> 8位预分频 ----> (16,32,64,128)再分频 ----> 产生计数脉冲进行计数 ----> 当计数器 WTCNT 加到0 或者减到0 时 ----> 产生中断,或者引起系统复位。
所以要每隔一段时间,就要喂狗,即重置 WTCNT 的值,防止 WTCNT 减到0。
2 驱动代码分析
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
2.1 devm_kzalloc: 内核内存分配函数
当device未连接(detached)或者driver被卸载(unloaded)时,该函数会自动释放分配好的内存
kzalloc() 也是内核内存分配函数,但必须配合kfree()使用,否则会造成内存泄漏
2.2 gfp flags
分配时内部最终会调用 __get_free_pages 来进行,简称GFP
2.2.1 GFP_KERNEL
这是最一般使用的标志,意思是这个分配代表运行在内核空间的进程,也就是说,调用GFP_KERNEL的函数是代表一个进程在执行一个系统调用。
使用 GFP_KENRL 意味着 kmalloc 能够使当前进程在少内存的情况下睡眠来等待一页. 一个使用 GFP_KERNEL 来分配内存的函数必须, 因此, 是可重入的并且不能在原子上下文中运行。当当前进程睡眠, 内核采取正确的动作来定位一些空闲内存, 或者通过刷新缓存到磁盘或者交换出去一个用户进程的内存.
GFP_KERNEL 不一直是使用的正确分配标志; 有时 kmalloc 从一个进程的上下文的外部调用. 例如, 这类的调用可能发生在中断处理, tasklet, 和内核定时器中. 在这个情况下, 当前进程不应当被置为睡眠, 并且驱动应当使用一个 GFP_ATOMIC 标志来代替. 内核正常地试图保持一些空闲页以便来满足原子的分配. 当使用 GFP_ATOMIC 时, kmalloc 能够使用甚至最后一个空闲页. 如果这最后一个空闲页不存在, 但是, 分配失败.
其他用来代替或者增添 GFP_KERNEL 和 GFP_ATOMIC 的标志, 尽管它们 2 个涵盖大部分设备驱动的需要. 所有的标志定义在 <linux/gfp.h>, 并且每个标志用一个双下划线做前缀, 例如 __GFP_DMA. 另外, 有符号代表常常使用的标志组合; 这些缺乏前缀并且有时被称为分配优先级. 后者包括:
GFP_ATOMIC
用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
GFP_KERNEL
内核内存的正常分配. 可能睡眠.
GFP_USER
用来为用户空间页来分配内存; 它可能睡眠.
GFP_HIGHUSER
如同 GFP_USER, 但是从高端内存分配, 如果有. 高端内存在下一个子节描述.
GFP_NOIO,GFP_NOFS
这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求. 一个 GFP_NOFS 分配不允许进行任何文件系统调用, 而 GFP_NOIO 根本不允许任何 I/O 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);