查看: 1252|回复: 0

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

[复制链接]
  • TA的每日心情
    开心
    3 天前
  • 签到天数: 597 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2021-4-19 21:08:34 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 robe.zhang 于 2021-4-19 21:25 编辑

    【百度大脑AI计算盒FZ5C】看门狗功能的实现

    先看看门狗硬件电路:一个 en 使能信号,一个 wdi 输入信号。
    他的工作原理是:en 高电平,wdi 信号有效,每过一秒 wdi 来个信号,硬件正常工作,如果 wdi 不来信号了,硬件认为软件死了,就去复位,这个复位动作是硬件完成了
    3.png
    使能信号随便一个 gpio 就可以完成,wdi 输入信号,如果使用 xilinx swdt 的话,需要 MIO 映射,映射的时候并不是每一个 MIO 都可以当作 wdi 的,一定要能映射到的 MIO 才可以。

    再看芯片:xilinx 有两个看门狗:
    2.png
    但是计算盒比较有意思,偏偏把可以映射的 mio6,7,10,11 当作 GPIO 用,不可以映射的 38 当作 wdi 用
    如果调换一下更好,但是硬件已经这样了,那就软件来补吧。
    1.png
    笔者在 5.4 内核版本中是这样实现的:修改一下设备树,en 使能端拉高,一直有效,系统心跳当作 wdi,如果死机系统心跳会停 wdi 没有信号,硬件自动复位。设备树配置如下:
    5.png
    测试方法和命令:

    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

    复制代码
    6.png


    米尔也有自己实现:
    4.png
    米尔是写了个 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);
    复制代码
    驱动自己会编译进内核,一开机看门狗就工作了,通过类属性文件调整开关看门狗功能,等
    7.png



    回复

    使用道具 举报

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

    本版积分规则

    关闭

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

    手机版|小黑屋|与非网

    GMT+8, 2024-11-23 12:55 , Processed in 0.117758 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.