TA的每日心情 | 开心 3 天前 |
---|
签到天数: 597 天 连续签到: 1 天 [LV.9]以坛为家II
|
本帖最后由 robe.zhang 于 2021-4-19 21:25 编辑
【百度大脑AI计算盒FZ5C】看门狗功能的实现
先看看门狗硬件电路:一个 en 使能信号,一个 wdi 输入信号。
他的工作原理是:en 高电平,wdi 信号有效,每过一秒 wdi 来个信号,硬件正常工作,如果 wdi 不来信号了,硬件认为软件死了,就去复位,这个复位动作是硬件完成了
使能信号随便一个 gpio 就可以完成,wdi 输入信号,如果使用 xilinx swdt 的话,需要 MIO 映射,映射的时候并不是每一个 MIO 都可以当作 wdi 的,一定要能映射到的 MIO 才可以。
再看芯片:xilinx 有两个看门狗:
但是计算盒比较有意思,偏偏把可以映射的 mio6,7,10,11 当作 GPIO 用,不可以映射的 38 当作 wdi 用
如果调换一下更好,但是硬件已经这样了,那就软件来补吧。
笔者在 5.4 内核版本中是这样实现的:修改一下设备树,en 使能端拉高,一直有效,系统心跳当作 wdi,如果死机系统心跳会停 wdi 没有信号,硬件自动复位。设备树配置如下:
测试方法和命令:
- echo none > /sys/class/leds/swd-wdi/trigger # 直接关闭看门狗,会重启
- echo 0 > /sys/class/leds/swd-en/brightness # 关闭看门狗功能,需要先失能,再关闭看门狗,不会重启
- echo none > /sys/class/leds/swd-wdi/trigger
- echo heartbeat > /sys/class/leds/swd-wdi/trigger # 打开看门狗功能,需要先开启看门狗,再使能
- echo 1 > /sys/class/leds/swd-en/brightness
复制代码
米尔也有自己实现:
米尔是写了个 gpio-watchdog 驱动实现,驱动中添加个时钟,时钟不停的反转 wdi 输出 pin,模拟 wdi 信号。同时导出类属性
- static int watchdog_probe(struct platform_device *pdev)
- {
- int ret = 0;
- gpdata = kmalloc(sizeof(struct watchdog_data), GFP_KERNEL);
- if(!gpdata) {
- printk(KERN_ERR "No memory!\n");
- return -ENOMEM;
- }
- memset(gpdata, 0, sizeof(struct watchdog_data));
- /* Init gpio */
- gpdata->gpio = DEFAULT_WDI;
- ret = gpio_request(DEFAULT_WDI, DEV_NAME);
- if(ret < 0) {
- printk(KERN_ERR "request gpio %d for %s failed!\n", DEFAULT_WDI, DEV_NAME);
- goto gpio_request_fail;
- }
- /* init wdt feed interval */
- gpdata->period = RESET_MS; /* Init period */
-
- initialize_timer(gpdata);
- /* Init class */
- gpdata->class.name = DEV_NAME;
- gpdata->class.owner = THIS_MODULE;
- gpdata->class.class_groups = watchdog_class_groups;
- ret = class_register(&gpdata->class);
- if(ret) {
- printk(KERN_ERR "class_register failed!\n");
- goto class_register_fail;
- }
-
- /* Start watchdog timer here */
- gpio_direction_output(gpdata->gpio, gpdata->gpio_value);
- mod_timer(&gpdata->timer, jiffies + msecs_to_jiffies(gpdata->period));
- gpdata->running = 1;
-
- printk(KERN_ALERT "%s driver initialized successfully!\n", DEV_NAME);
- return 0;
- class_register_fail:
- destroy_timer(gpdata);
- gpio_free(gpdata->gpio);
-
- gpio_request_fail:
- kfree(gpdata);
-
- return ret;
- }
复制代码- static void initialize_timer(struct watchdog_data * pdata)
- {
- if(!pdata) {
- printk(KERN_ERR "Watchdog device has not been initialized yet.\n");
- return;
- }
- if (pdata->period <= 0) {
- pdata->period = RESET_MS;
- }
- timer_setup( &pdata->timer, reset_watchdog, 0 );
- }
复制代码 反转 wdi 信号
- static void reset_watchdog(struct timer_list *t)
- {
- struct watchdog_data * pdata = from_timer(pdata, t, timer);
-
- pdata->gpio_value ^= 0x1;
- gpio_direction_output(pdata->gpio, pdata->gpio_value);
- mod_timer(&pdata->timer, jiffies + msecs_to_jiffies(pdata->period));
- // printk(KERN_ALERT "- reset wd.\n");
- }
复制代码 类属性导出:
- /* class attribute show function. */
- static ssize_t watchdog_show(struct class *cls, struct class_attribute *attr, char *buf)
- {
- struct watchdog_data *pdata = (struct watchdog_data *)container_of(cls, struct watchdog_data, class);
- return sprintf(buf, "%d\n", pdata->running?pdata->period:0);
- }
- /* class attribute store function. */
- static ssize_t watchdog_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count)
- {
- struct watchdog_data *pdata = (struct watchdog_data *)container_of(cls, struct watchdog_data, class);
- int tmp;
-
- if(!buf || sscanf(buf, "%d", &tmp) <= 0) {
- return -EINVAL;
- }
-
- if(tmp == 0 && pdata->running) { /* Stop the watchdog timer */
- del_timer(&pdata->timer);
- pdata->running = 0;
-
- /* Set gpio to input(High-Z state) to disable external watchdog timer */
- gpio_direction_input(pdata->gpio);
-
- printk("Cancel watchdog timer!\n");
- } else if(tmp > 0) {
- printk(KERN_ALERT "Set period to %d ms .\n", tmp);
- pdata->period = tmp;
- if(!pdata->running) {
- printk(KERN_ALERT "Start WD timer.\n");
- mod_timer(&pdata->timer, jiffies + msecs_to_jiffies(pdata->period));
- pdata->running = 1;
- }
- } else {
- return -EINVAL;
- }
-
- return count;
- }
- struct class_attribute class_attr_watchdog = __ATTR(wd_period_ms, S_IRUGO | S_IWUSR , watchdog_show, watchdog_store);
- static ssize_t feed_show(struct class *cls, struct class_attribute *attr, char *buf)
- {
- return sprintf(buf, "write '1' to enable manual-mode and disable auto-mode.\n");
- }
- static ssize_t feed_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count)
- {
- struct watchdog_data *pdata = (struct watchdog_data *)container_of(cls, struct watchdog_data, class);
- int tmp;
- if(!buf || sscanf(buf, "%d", &tmp) <= 0) {
- return -EINVAL;
- }
-
- if(tmp == 0) {
- if(pdata->running == 0) {
- printk(KERN_ALERT "Cancel watchdog.\n");
- /* Set gpio to input(High-Z state) to disable external watchdog timer */
- gpio_direction_input(pdata->gpio);
- } else {
- printk(KERN_ALERT "Can not cancel watchdog by writing 'wd_feed' while running in auto-mode.\n");
- }
- } else if(tmp > 0) {
- if(pdata->running) {
- printk(KERN_ALERT "Disable auto-mode and switch to manual-mode.\n");
- del_timer(&pdata->timer);
- pdata->running = 0;
- }
- pdata->gpio_value ^= 0x1;
- gpio_direction_output(pdata->gpio, pdata->gpio_value);
- } else {
- return -EINVAL;
- }
- return count;
- }
- struct class_attribute class_attr_feed = __ATTR(wd_feed, S_IRUGO | S_IWUSR , feed_show, feed_store);
- /* Attributes declaration: Here I have declared only one attribute attr1 */
- static struct attribute *watchdog_class_attrs[] = {
- &class_attr_watchdog.attr,
- &class_attr_feed.attr,
- NULL,
- };
- ATTRIBUTE_GROUPS(watchdog_class);
复制代码 驱动自己会编译进内核,一开机看门狗就工作了,通过类属性文件调整开关看门狗功能,等
|
|