前言
我们知道 Watchdog 对故障检测和系统恢复都至关重要,但是如果对 MPU 的 Watchdog 在Linux 系统下是如何工作的不是很了解,就不会让 Watchdog 发挥它该有的作用,所以接下来大概讲解一下如何测试和使用 linux 系统下的 Watchdog。
1、概括
MP13x/MP15x有两路独立的看门狗(IWDG1, IWDG2),其中只有IWDG1才可以被配置到安全区域下访问。独立看门狗是由LSI提供时钟,外部独立的32kHz的RC提供时钟源,所以能保证看门狗在整个MPU系统中独立安全可靠的运行。另外MP15x还有一个窗口看门狗(WWDG),可以作为Cortex-M4协处理器的Watchdog,Watchdog还可以作为定时器和低功耗唤醒源,但是这篇LAT不会讨论相关话题。
2、工作原理
对 Watchdog 的寄存器配置和中断响应依赖的是 APB 时钟,所以在配置 Watchdog 之前,需要先对 APB 时钟进行使能(IWDG1 总线时钟是通过 IWDG1APBEN 和 IWDG1APBLPEN 位来控制,同理 IWDG2 总线时钟是通过 IWDG2APBEN 和 IWDG2APBLPEN 位来使能),另外Watchdog 的运行时钟是由 LSI RC 提供。
默认的 Watchdog 工作方式是,一旦 Watchdog 使能,IWDCNT 就开始向下计数,当这个值从默认的 0xFFF 变为 0x000 时就会产生 iwdg_out_rst 信号,可以使系统重启。所以在IWDCNT 在变为 1 之前就需要刷新 Watchdog 防止系统 reset,这里通过把 0x0000AAAA 写入IWDG_KR 寄存器来刷新 IWDCNT 恢复默认值 0xFFF。由于 Linux 系统很难做到和裸跑程序一样的实时性,所以喂狗时间尽可能的提前,不宜无限接近 Watchdog 的 timeout 时间。
关于喂狗时间,由上面的简单描述可以知道,IWDCNT 的默认值 0xFFF 是 Watchdog 的最大超时喂狗时间(窗口看门狗是另外的设计),所以可以通过 IWDG_PR 寄存器来配置 LSI 运行时钟的 Prescaler divider,从而配置需要的最大超时时间。例如,默认的 Watchdog 工作时钟源是 32Khz LSI RC,如果把 IWDG_PR 寄存器配置为 0x6(divider / 256),那么 Watchdog 工作时钟就变为 125Hz,IWDCNT 从 0xFFF 变为 0x000 就需要(1/125)*4095 约等于 32 秒钟。
3、注意问题
1) 一旦 watchdog 使能了,整个系统从 tf-a 到 Linux kernel 各个 启动阶段都需要不断的喂狗,所以当任何一个启动阶段卡顿时间超过喂狗的周期,就会触发 watchdog 重启。需要注意的是,尽量不要停掉 kernel 内部的定时器喂狗程序。同时需要注意,当应用程序通过/dev/watchdog 设备节点,打开看门狗后,Linux kernel 就停掉定时器喂狗,把喂狗执行交给应用程序,所以这个时候外部的喂狗程序不能中断。
2) 前面一直提到 TF-A 打印可以查看到重启的原因,重启原因是通过 RCC_MP_RSTSCLRR寄存器来判断的,如果打印的原因一直是 power-on reset,并没有看到 watchdog 触发的原因。主要因为在 watchdog 重启系统的时候,可能是外部的 VDD 供电被重启过,导致 MPU 的状态恢复到冷启动状态。所以这边硬件要注意 MPU 重启的时候,尽量不要重启 VDD 供电。
4、总结
从 OSTL4.0 开始,Linux kernel 阶段和 U-Boot 阶段都是通过 smc 服务接口调用 optee 安全区域的 Watchdog 来配置和喂狗的,Linux 可以参考 drivers/watchdog/arm_smc_wdt.c 源码。旧版本的 Watchdog 使用的是 IWDG2,U-Boot 驱动(drivers/watchdog/stm32mp_wdt.c)和 Linux 驱动(drivers/watchdog/stm32_iwdg.c)直接调用 Watchdog 的寄存器(KR,PR,RLR 等)来实现。另外需要注意,默认的 systemd是配置看门狗的,如果发现/dev/watchdog 设备节点不让访问,需要根据上文提到的方法来关闭 systemd 的喂狗程序。一旦应用程序接管了喂狗程序,喂狗不能中断。