回答

收藏

[评测分享] 【百度大脑AI计算盒FZ5C】看门狗功能的实现

#板卡评测 #板卡评测 2097 人阅读 | 0 人回复 | 2021-04-19

本帖最后由 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 没有信号,硬件自动复位。设备树配置如下:

测试方法和命令:

  1. echo none > /sys/class/leds/swd-wdi/trigger                # 直接关闭看门狗,会重启

  2. echo 0 > /sys/class/leds/swd-en/brightness                # 关闭看门狗功能,需要先失能,再关闭看门狗,不会重启
  3. echo none > /sys/class/leds/swd-wdi/trigger

  4. echo heartbeat > /sys/class/leds/swd-wdi/trigger        # 打开看门狗功能,需要先开启看门狗,再使能
  5. echo 1 > /sys/class/leds/swd-en/brightness

复制代码



米尔也有自己实现:

米尔是写了个 gpio-watchdog 驱动实现,驱动中添加个时钟,时钟不停的反转 wdi 输出 pin,模拟 wdi 信号。同时导出类属性
  1. static int watchdog_probe(struct platform_device *pdev)
  2. {
  3.         int ret = 0;

  4.         gpdata = kmalloc(sizeof(struct watchdog_data), GFP_KERNEL);
  5.         if(!gpdata) {
  6.                 printk(KERN_ERR "No memory!\n");
  7.                 return -ENOMEM;
  8.         }
  9.         memset(gpdata, 0, sizeof(struct watchdog_data));

  10.         /* Init gpio */        
  11.         gpdata->gpio = DEFAULT_WDI;

  12.         ret = gpio_request(DEFAULT_WDI, DEV_NAME);
  13.         if(ret < 0) {
  14.                 printk(KERN_ERR "request gpio %d for %s failed!\n", DEFAULT_WDI, DEV_NAME);
  15.                 goto gpio_request_fail;
  16.         }

  17.         /* init wdt feed interval */
  18.         gpdata->period = RESET_MS; /* Init period */
  19.         
  20.         initialize_timer(gpdata);

  21.         /* Init class */
  22.         gpdata->class.name = DEV_NAME;
  23.         gpdata->class.owner = THIS_MODULE;
  24.         gpdata->class.class_groups = watchdog_class_groups;
  25.         ret = class_register(&gpdata->class);
  26.         if(ret) {
  27.                 printk(KERN_ERR "class_register failed!\n");
  28.                 goto class_register_fail;
  29.         }
  30.         
  31.         /* Start watchdog timer here */
  32.         gpio_direction_output(gpdata->gpio, gpdata->gpio_value);
  33.         mod_timer(&gpdata->timer, jiffies + msecs_to_jiffies(gpdata->period));
  34.         gpdata->running = 1;
  35.         
  36.         printk(KERN_ALERT "%s driver initialized successfully!\n", DEV_NAME);
  37.         return 0;

  38. class_register_fail:
  39.         destroy_timer(gpdata);
  40.         gpio_free(gpdata->gpio);
  41.         
  42. gpio_request_fail:
  43.         kfree(gpdata);
  44.         
  45.         return ret;
  46. }
复制代码
  1. static void initialize_timer(struct watchdog_data * pdata)
  2. {
  3.         if(!pdata) {
  4.                 printk(KERN_ERR "Watchdog device has not been initialized yet.\n");
  5.                 return;
  6.         }

  7.         if (pdata->period <= 0) {
  8.                 pdata->period = RESET_MS;
  9.         }

  10.         timer_setup( &pdata->timer, reset_watchdog, 0 );

  11. }
复制代码
反转 wdi 信号
  1. static void reset_watchdog(struct timer_list *t)
  2. {
  3.         struct watchdog_data * pdata = from_timer(pdata, t, timer);
  4.         
  5.         pdata->gpio_value ^= 0x1;
  6.         gpio_direction_output(pdata->gpio, pdata->gpio_value);
  7.         mod_timer(&pdata->timer, jiffies + msecs_to_jiffies(pdata->period));
  8. //        printk(KERN_ALERT "- reset wd.\n");
  9. }
复制代码
类属性导出:
  1. /* class attribute show function. */
  2. static ssize_t watchdog_show(struct class *cls, struct class_attribute *attr, char *buf)
  3. {
  4.         struct watchdog_data *pdata = (struct watchdog_data *)container_of(cls, struct watchdog_data, class);
  5.         return sprintf(buf, "%d\n", pdata->running?pdata->period:0);
  6. }

  7. /* class attribute store function. */
  8. static ssize_t watchdog_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count)
  9. {
  10.         struct watchdog_data *pdata = (struct watchdog_data *)container_of(cls, struct watchdog_data, class);
  11.         int tmp;
  12.         
  13.         if(!buf || sscanf(buf, "%d", &tmp) <= 0) {
  14.                 return -EINVAL;
  15.         }
  16.         
  17.         if(tmp == 0 && pdata->running) { /* Stop the watchdog timer */
  18.                 del_timer(&pdata->timer);
  19.                 pdata->running = 0;
  20.                
  21.                 /* Set gpio to input(High-Z state) to disable external watchdog timer */
  22.                 gpio_direction_input(pdata->gpio);
  23.                
  24.                 printk("Cancel watchdog timer!\n");
  25.         } else if(tmp > 0) {
  26.                 printk(KERN_ALERT "Set period to %d ms .\n", tmp);
  27.                 pdata->period = tmp;
  28.                 if(!pdata->running) {
  29.                         printk(KERN_ALERT "Start WD timer.\n");
  30.                         mod_timer(&pdata->timer, jiffies + msecs_to_jiffies(pdata->period));
  31.                         pdata->running = 1;
  32.                 }
  33.         } else {
  34.                 return -EINVAL;
  35.         }
  36.         
  37.         return count;
  38. }
  39. struct class_attribute class_attr_watchdog = __ATTR(wd_period_ms, S_IRUGO | S_IWUSR , watchdog_show, watchdog_store);

  40. static ssize_t feed_show(struct class *cls, struct class_attribute *attr, char *buf)
  41. {
  42.         return sprintf(buf, "write '1' to enable manual-mode and disable auto-mode.\n");
  43. }

  44. static ssize_t feed_store(struct class *cls, struct class_attribute *attr, const char *buf, size_t count)
  45. {
  46.         struct watchdog_data *pdata = (struct watchdog_data *)container_of(cls, struct watchdog_data, class);
  47.         int tmp;
  48.         if(!buf || sscanf(buf, "%d", &tmp) <= 0) {
  49.                 return -EINVAL;
  50.         }
  51.         
  52.         if(tmp == 0) {
  53.                 if(pdata->running == 0) {
  54.                         printk(KERN_ALERT "Cancel watchdog.\n");
  55.                         /* Set gpio to input(High-Z state) to disable external watchdog timer */
  56.                         gpio_direction_input(pdata->gpio);
  57.                 } else {
  58.                         printk(KERN_ALERT "Can not cancel watchdog by writing 'wd_feed' while running in auto-mode.\n");
  59.                 }
  60.         } else if(tmp > 0) {
  61.                 if(pdata->running) {
  62.                         printk(KERN_ALERT "Disable auto-mode and switch to manual-mode.\n");
  63.                         del_timer(&pdata->timer);
  64.                         pdata->running = 0;
  65.                 }
  66.                 pdata->gpio_value ^= 0x1;
  67.                 gpio_direction_output(pdata->gpio, pdata->gpio_value);
  68.         } else {
  69.                 return -EINVAL;
  70.         }
  71.         return count;
  72. }
  73. struct class_attribute class_attr_feed = __ATTR(wd_feed, S_IRUGO | S_IWUSR , feed_show, feed_store);

  74. /* Attributes declaration: Here I have declared only one attribute attr1 */
  75. static struct attribute *watchdog_class_attrs[] = {
  76.         &class_attr_watchdog.attr,
  77.         &class_attr_feed.attr,
  78.         NULL,
  79. };
  80. ATTRIBUTE_GROUPS(watchdog_class);
复制代码
驱动自己会编译进内核,一开机看门狗就工作了,通过类属性文件调整开关看门狗功能,等




分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条