上一篇介绍了watchdog实现框架,不同厂家soc提供的实现会有所差异,但是整体流程还是在框架范围内。以项目中具体的实践进一步说明watchdog的功能,很多车企都在使用qcom的SA8295芯片,本文也以此为例。

流程图

SA8295芯片是和qnx系统绑定的,系统层面一般是采用Q+L或Q+A的架构,即host端为QNX,guest端为linux(或android)。watchdog模块在host和guest都有实现,host端虚拟设备vdev驱动充当硬件,guest端需要定期发送心跳信号(pet)重置host端的vdev。

为了对比watchdog通用框架中的实现,需要对qcom实现中的名词进行解释下:

pet:'投食',由guest端发起,同义的有:ping、heartbeat,都是指心跳信号;

bark:'狗叫',由host端发起,通用框架中pretimeout回调的功能,收集重启前的信息;

bite:'狗咬',由host端发起,通用框架中timeout触发的功能,重启设备;

流程:

guest喂狗进程msm-watchdog定期发送pet信号,重置host端的定时器;

当guest系统异常导致无法发送pet信号,barktimeout后会发送irq到guest端,guest端msm-watchdog收到中断后收集信息用于问题分析;

步骤2收集完后等待bite重启guest,图中的vmm为虚拟机管理器,管理guest的启动、停止等生命周期。

guest实现

分为watchdog驱动(qcom_soc_)和watchdogcore框架(qcom_wdt_)2部分。

黄色:core框架实现;绿色:驱动实现

入口:watchdog设备首先会执行qcom_soc_wdt_probe进行初始化;

每种具体的watchdog型号都会有对应实现的操作集:qcom_soc_wdt_ops

qcom_soc_set_wdt_bark:设置barktimeout时间,宏QCOM_WATCHDOG_BARK_TIME(11s)定义;qcom_soc_set_wdt_bite:设置bitetimeout时间,qcom实现为bark_timeout+3000(14s);qcom_soc_reset_wdt:重启watchdog;qcom_soc_enable_wdt:开启watchdog;qcom_soc_disable_wdt:停止watchdog;qcom_soc_show_wdt_status:获取watchdogstatus信息;

调用框架提供的qcom_wdt_register方法提供了主要的实现。原型如下,其中wdog_dd_name为msm-watchdog,即喂狗线程的名字。

intqcom_wdt_register(structplatform_device*pdev,structmsm_watchdog_data*wdog_dd,char*wdog_dd_name)
qcom_wdt_dt_to_pdata:

赋值watchdog关键字段:

bark_irq:bark_time超时后guest会发送irq给guest,值有定义:

_base0x17C10000wdt_hz32765wdt_bark_irq32wdt_bite_irq33

bark_time:通用框架中的pretimeout,当该时间到期后会收集信息,值是有宏QCOM_WATCHDOG_BARK_TIME定义,默认为11s;

pet_time:喂狗间隔,定期向host发送心跳(heartbeat)信号,值是有宏QCOM_WATCHDOG_PET_TIME定义,默认为9.360s;

do_ipi_ping:当msm-watchdog向host发送心跳信号,所在的localcpu同时也会向其他cpu发送ping信号,让其他cpu保持活跃状态,值是有宏QCOM_WATCHDOG_IPI_PING定义,默认为true;

wakeup_irq_enable:系统susp和resume时,watchdog会自动停止和恢复,值是有宏QCOM_WATCHDOG_WAKEUP_ENABLE定义,默认为true;

msm-watchdog

kthread_create创建喂狗进程,间隔pet_time向host发送心跳信号。实现上和通用watchdog架构类似,逻辑也不复杂。

qcom_wdt_init

该处的实现比较重要,上图对其中的主要步骤进行了列举。

注:部分函数参数进行了简略以便突出关键点。

devm_request_irq

申请bark中断号和中断处理函数qcom_wdt_bark_handler,中断号为32,触发方式为IRQF_TRIGGER_RISING(上升沿),中断名字为apps_wdog_bark。当barktimeout后guest会收到中断并执行qcom_wdt_bark_handler函数:

[IVI]#cat/proc/interruptsCPU0CPU1CPU2CPU3CPU4CPU5CPU6CPU710:00000000GICv332Edgeapps_wdog_bark

qcom_wdt_bark_handler主要用于收集信息,并等待bite中断重启:

[1481.289810]msm_,wdt:QCOMAppsWatchdogbark!Now=1481.289807[1481.289812]msm_,wdt:[1481.289814]msm_,wdt:cpualivemaskfromlastpet1f[1481.289815]msm_,wdt:CausingaQCOMAppsWatchdogbite![1481.290591]msm_,wdt:Wdog-STS:0xffffffff,CTL:0xffffffff,BARKTIME:0xffffffff,BITETIME:0xffffffff

set_bark_time和set_bite_time

设置bark_timeout和bite_tiemout值,值是由前面的qcom_wdt_dt_to_pdata初始化的,下面也说明了bark后预留了一部分时间用于收集信息才会reset系统。这里也是通用框架中pretimeout的实现场景之一。

bite_tiemout=bark_timeout+3000ms

qcom_wdt_panic_handler

注册panicnotifier通知链,即发生panic时会触发链表上的回调函数。该功能比较实用,可以自定义一些行为,如收集内存信息,cpu信息等。该处的回调实现为qcom_wdt_panic_handler:

staticintqcom_wdt_panic_handler(structnotifier_block*this,unsignedlongevent,void*ptr){if(panic_timeout==0){wdog_dd-ops-disable_wdt(wdog_dd);}else{qcom_wdt_reset_on_oops(wdog_dd,panic_timeout);}}staticvoidqcom_wdt_reset_on_oops(structmsm_watchdog_data*wdog_dd,inttimeout){wdog_dd-ops-set_bark_time((timeout+10)*1000,wdog_dd);wdog_dd-ops-set_bite_time((timeout+10)*1000,wdog_dd);}

如果定义了panic_timeout(如通过宏CONFIG_PANIC_TIMEOUT或者cmdline),即发生panic后等待多久重启。不为0的情况下会在qcom_wdt_reset_on_oops设置bark和bitetimeout时间,触发bark会延迟panic_timeout+10;

qcom_wdt_pet_task_wakeup

启动喂狗定时器,同通用框架中实现。pet_timer为9.360s,定时器结束后触发qcom_wdt_pet_task_wakeup

//1.设置定时器函数timer_setup(wdog_dd-pet_timer,qcom_wdt_pet_task_wakeup,0);//2.定时器到期后唤醒msm-watchdogstaticvoidqcom_wdt_pet_task_wakeup(structtimer_list*t){wake_up(wdog_dd-pet_complete);}//3.执行qcom_wdt_kthreadstatic__refintqcom_wdt_kthread(void*arg){while(!kthread_should_stop()){do{ret=wait_event_interruptible(wdog_dd-pet_complete,wdog_dd-timer_expired);}while(ret!=0);
结束

这篇主要介绍了sa8295watchdogguest端实现,主要流程应该大致清楚了,可以对比通用框架和qcom实现的相同点和差异点。host端涉及也较多,放在下一篇介绍。