2Uboot添加硬件看门狗
uboot中默认看门狗策略由两个宏CONFIG_HW_WATCHDOG和CONFIG_WATCHDOG来使能。
此策略是在代码执行中的不同阶段,添加喂狗代码。
这种喂狗方法会使代码很乱,uboot中到处都充斥的喂狗代码。另外这种方法对代码执行时间是敏感的,如果有段代码执行时间很长(如搬运code),则需要添加喂狗代码,很繁。
uboot的默认策略比较适合外部看门狗。
我们现在用的是CPU内部看门狗,直接无视上述两宏。我们要在watchdog interrupt中喂狗,即只在watchdog interrupt handler中喂狗,比较简便。
2.1Watchdog Interrupt Handler
修改文件uboot/cpu/mpc85xx/start.S,修改默认的handler
- /* STD_EXCEPTION(0x0c00, WatchdogTimer, UnknownException) */
- STD_EXCEPTION(0x0c00, WatchdogTimer, WatchdogHandler)
修改文件uboot/cpu/mpc85xx/traps.c,实现自己的handler
- void WatchdogHandle(struct pt_regs*regs){
- unsigned long msr;//turn off all interrpt, may need it, not sure
- msr = get_msr();
- set_msr(0);
- mtspr(SPRN_TSR, mfspr(SPRN_TSR)| TSR_WIS);//喂狗
- set_msr(msr);
- }
2.2Watchdog 配置及开启
修改uboot/lib_ppc/board.c,添加watchdog的配置及开启例程
- init_fnc_t*init_sequence[]=
- {
- ………
- WatchdogCreate,//配置例程 这两个例程越靠前越好,没有强制要求
- WatchdogStart,//开启例程
- ……
- };
修改uboot/common/cmd_bootm.c,添加watchdog的配置例程,开启例程和暂停例程
- void WatchdogCreate(void)
- {
- unsigned long register val;
- //01.no time base counting now
- mtspr(SPRN_HID0, mfspr(SPRN_HID0)& ~HID0_TBEN);
- //02.set timer period
- val = mfspr(SPRN_TCR);
- val &= ~(0xc0000000| 0x001e0000);// clear WP and WP_EXT
- val |= (0x00120000);// 此处可修改为宏实现
- mtspr(SPRN_TCR, val);
- //03.set period unit
- val = mfspr(SPRN_HID0);
- val &= ~(0x00040000);
- mtspr(SPRN_HID0, val);
- //04. enable Watchdog timer interrupt
- set_msr (get_msr()| MSR_CE);
- //05: enable watchdog timer
- mtspr(SPRN_TCR, mfspr(SPRN_TCR)| TCR_WIE);
- //06: deal with sec timer out
- val = mfspr(SPRN_TCR);
- val &= ~30000000;
- val |= 0x20000000;//reboot
- mtspr(SPRN_TCR, val);
- asm("isync");
- }
- void WatchdogStart(void)
- {
- //01. clear time base
- mtspr(SPRN_TBWL, 0);
- mtspr(SPRN_TBWU, 0);
- //02. now time base counting...
- mtspr(SPRN_HID0, mfspr(SPRN_HID0)| HID0_TBEN);
- asm("isync");
- }
- void WatchdogStop(void){// just for test,need to modify and more test
- //01. clear tsr
- mtspr( SPRN_TSR, 0xf0000000);
- //02.clear watchdog timer period
- mtspr( SPRN_TCR, mfspr(SPRN_TCR)& ~(0xc0000000| 0x001e0000) );
- //03.disable watchdog timer
- mtspr(SPRN_TCR, mfspr(SPRN_TCR)& ~(TCR_WIE));
- }
2.3reset命令的实现
现在我们可以用wathdog来实现重启命令reset。
修改文件 uboot/cpu/mpc85xx/cpu.c
- int do_reset(cmd_tbl_t *cmdtp, bd_t*bd, int flag, int argc,char *argv[])
- {
- #if 0 // leon del for HRESET
- /*
- * Initiate hard reset in debug control register DBCR0
- * Make sure MSR[DE] = 1
- */
- unsigned long val;
- val = mfspr(DBCR0);
- val |= 0x70000000;
- mtspr(DBCR0,val);
- #endif
- //leon add: just disable first time out,second time out will reset send HRESET_REQ
- mtspr(SPRN_TCR, mfspr(SPRN_TCR)& ~TCR_WIE);
- return 1;
- }
2.4FLASH操作关闭看门狗 (??)
打开看门狗的话,对Flash进行写操作时,会使uboot崩溃。具体原因还没找到,一个比较靠谱的猜想是watchdog interrpt handler代码执行还会去flash中读指令。可是当你敲erase bank 1命令的时候,代码早就搬运到RAM中了啊,无解。。。望牛人指点,感激不尽。
所以,当对flash进行写操作指令前,首先要敲自己加的命令,如timer_stop,来关闭watchdog。
写操作完成后,敲命令timer_start,来启动watchdog。
命令timer_stop中再去调函数WatchdogStop().命令timer_start中调用WatchdogCreate()和WatchdogStart()
具体命令如何添加,参考
uboot添加命令,最快最简山寨法
3Linux添加硬件看门狗
Linux中watchdog机制是靠uboot传来的wdt和wdt_period启动参数来使能的。
wdt为1就使能watchdog机制,0就禁止;
wdt_perid就是上面所说的period值了。
WDT的配置和开启是在wdt驱动里实现的,入口函数是booke_wdt_init()
Linux的watchdog interrupt handler函数WatchdogException()会自旋直至CPU硬复位。
那我们在Decrementer Interrupt handler中喂狗,即在do_timer()中喂狗。
修改文件linux-2.6.24/kernel/timer.c
- externint stop_feed;
- void do_timer(unsignedlong ticks)
- {
- if( likely(stop_feed== 0))
- mtspr(SPRN_TSR, mfspr(SPRN_TSR)| TSR_WIS);//喂狗
- jiffies_64 += ticks;
- update_times(ticks);
- }
相应的reboot命令的实现就简单多了,文件linux-2.6.24/arch/ppc/syslib/ppc85xx_setup.c
- void mpc85xx_restart(char*cmd){
- local_irq_disable();
- myabort();
- }
- int stop_feed= 0;
- void myabort(void){
- stop_feed = 1;
- }
修改到此结束。
当我们敲reboot命令后,do_timer()中停止喂狗,watchdog timer first time out后,会执行Watchdog interrupt handler函数 WatchdogException(),then spin until second timeout occur,then reboot。
//文件linux-2.6.24/arch/ppc/kernel/head_fsl_booke.S
- CRITICAL_EXCEPTION(0x3200, WatchdogTimer, WatchdogException)
//文件linux-2.6.24/arch/ppc/kernel/traps.c
- void WatchdogException(struct pt_regs*regs)
- {
- printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n");
- WatchdogHandler(regs);
- }
- /*
- * Default handler for a Watchdog exception,
- * spins until a reboot occurs 这句和CRITICAL_EXCEPTION宏有关
- */
- void __attribute__((weak)) WatchdogHandler(struct pt_regs*regs)
- {
- /* Generic WatchdogHandler, implement your own */
- mtspr(SPRN_TCR, mfspr(SPRN_TCR)&(~TCR_WIE));//
- return;
- }