Linux - 驱动开发 - watchdog - SMP机制下多核确活

说明

  • 理论上:不管IC是单核还是多核,只要watchdog有被循环feed,就不会触发超时重启,因此watchdog在SMP机制下的多核环境显得比较宽松,只要任意核存活(喂狗)就不会重启设备。

实际情况

  • 有客户反馈,多核环境下(SMP机制管理)有核hang住了,但是设备没有重启。
  • 在SMP机制管理的8核arm平台上实测现象:
  1. 有核crash(特意使核上跑的程序crash),SMP能检测到,并且所有核都会被stop,watchdog能重启设备。

  2. 有核hang住(特意使核上跑的程序hang住),设备会非常卡,smp机制中的调度会每隔一段时间打印一次timeout,但是由于主核正常,喂狗正常,不会触发watchdog重启系统,如下:

    [ 433.562934] rcu: INFO: rcu_sched detected stalls on CPUs/tasks:
    [ 433.568883] rcu: 1-...0: (16 ticks this GP) idle=e3a/0/0x3 softirq=98/98 fqs=10498
    [ 433.576660] (detected by 0, t=21007 jiffies, g=-935, q=16)
    [ 433.582255] Task dump for CPU 1:
    [ 433.585495] task:swapper/1 state:R running task stack:15152 pid: 0 ppid: 1 flags:0x0000000a
    [ 433.595460] Call trace:
    [ 433.597917] __switch_to+0xb8/0xe8
    [ 433.601332] 0xffffff8100130c00

  • 根据一些测试现象推测:有核卡住,设备非常卡是因为smp调度时,调度过程是阻塞的(但是有超时),smp调度过程就会卡住很久,只有超时后,其它进程才能得到调度,将触发smp调度的操作放到wdt驱动的喂狗函数中,这样就会触发watchdog重启系统,smp调度阻塞住喂狗了。

结论

  • IC生产,无法确保每个核都是一样稳定,如果多核IC中有少数核稳定性稍微差点,可能会出现部分核hang住,因此需要watchdog来检测这种情况并重启。

实现

  • 同构多核使用SMP机制管理下,kenerl启动之前只有主核在运行,kernel启动过程中再由kernel bringup其它核,因此kernel运行前的固件(uboot等),不需要做检测。

SMP机制下多核确活机制(严格模式)

  • 在多核SMP管理环境下,确认多核是否alive,只要任意核hang住,重启设备。

思路

  • 通过SMP机制发送核间中断给每个核,每个核收到中断后,将一个全局CPU 位图变量打上标志,表示核正在运行。

  • 发送核间中断,让每个核执行同一个函数:

    // 每个核都会运行该函数
    static void cpu_alive(void *passed_regs)
    {
    ...
    }

    smp_call_function(cpu_alive, NULL, 0);
    smp_wmb();

  • 第一版做法:每次喂狗前,发送SMP调度请求,等待所有核运行完成。

    static cpumask_t cpus_alive = CPU_MASK_NONE;

    #ifdef CONFIG_SMP
    static void cpu_alive(void *passed_regs)
    {
    int cpu = smp_processor_id();

    复制代码
      pr_debug("cpu[%d] setmask \n", cpu);
      cpumask_set_cpu(cpu, &cpus_alive);

    }
    #endif

    // watchdog驱动喂狗函数
    static int dw_wdt_ping(struct watchdog_device *wdd)
    {
    struct dw_wdt *dw_wdt = to_dw_wdt(wdd);

    #ifdef CONFIG_SMP
    unsigned int msecs;
    unsigned int ncpus;

    复制代码
      cpus_alive = CPU_MASK_NONE;
    
      ncpus = num_online_cpus() - 1;
      
      pr_debug("Sending IPI to other cpus...\n");
      smp_call_function(cpu_alive, NULL, 0);
      smp_wmb();
    
      // 阻塞1s 等待所有核执行完成
      msecs = 1000; // 1s
      while ((cpumask_weight(&cpus_alive) < ncpus) && (--msecs > 0)) {
          cpu_relax();
          mdelay(1);
      }
    
      if (cpumask_weight(&cpus_alive) >= ncpus)

    #endif
    writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt->regs
    + WDOG_COUNTER_RESTART_REG_OFFSET);

    复制代码
      return 0;

    }

  • 问题

  1. 阻塞1s,等待所有核执行完成,如果存在核执行超时了,会导致误判。
  2. 如果将阻塞时间拉长,喂狗时间和wdt timeout时间需要空出该时间。
  • 新版本:每次喂狗前,检查上一次喂狗后发送SMP调度请求后的CPU 位图数据,喂狗,再发送一次SMP调度请求。

    static cpumask_t cpus_alive = CPU_MASK_NONE;

    #ifdef CONFIG_SMP
    static void cpu_alive(void *passed_regs)
    {
    int cpu = smp_processor_id();

    复制代码
      pr_debug("cpu[%d] setmask \n", cpu);
      cpumask_set_cpu(cpu, &cpus_alive);

    }
    #endif

    static int dw_wdt_ping(struct watchdog_device *wdd)
    {
    struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
    static int isFirst = 1;

    #ifdef CONFIG_SMP
    unsigned int ncpus;

    复制代码
      ncpus = num_online_cpus() - 1;
    
      if ((isFirst == 1) || cpumask_weight(&cpus_alive) >= ncpus) {

    #endif
    writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt->regs +
    WDOG_COUNTER_RESTART_REG_OFFSET);

    #ifdef CONFIG_SMP
    isFirst = 0;
    cpus_alive = CPU_MASK_NONE;
    smp_call_function(cpu_alive, NULL, 0);
    smp_wmb();
    }
    #endif

    复制代码
      return 0;

    }

  • 好处:等待所有核执行SMP请求和间隔喂狗并行起来了,不必像串行一样,多花一个等待时间。

相关推荐
人猿泰飞22 分钟前
在Ubuntu-22.04.5中安装ONLYOFFICE DocSpace(协作空间)【注意:安装失败,谨慎参考!】
java·linux·运维·python·ubuntu·项目管理·onlyoffice
CAE虚拟与现实23 分钟前
修改wsl中发行版Ubuntu的主机名
linux·运维·ubuntu·wsl·wsl2·修改主机名
开发小能手-roy26 分钟前
Ubuntu服务器性能调优指南:从基础工具到系统稳定性提升
linux·运维·服务器·ubuntu
潘yi.34 分钟前
Shell编程之正则表达式与文本处理器
linux·运维·正则表达式
涛涛讲AI41 分钟前
wkhtmltopdf 实现批量对网页转为图片的好工具,快速实现大量卡片制作
linux·服务器·windows·windows效率工具
破刺不会编程1 小时前
什么是进程?
linux·运维·服务器
大数据魔法师2 小时前
Redis(一) - Redis安装教程(Windows + Linux)
linux·windows·redis
Y1anoohh2 小时前
驱动学习专栏--字符设备驱动篇--2_字符设备注册与注销
linux·c语言·驱动开发·学习
.R^O^2 小时前
计算机知识
linux·服务器·网络·安全
卡戎-caryon3 小时前
【Linux网络与网络编程】11.数据链路层mac帧协议&&ARP协议
linux·服务器·网络·笔记·tcp/ip·数据链路层