FreeBSD/mipsのMediatekにwatchdogの実装がなかったので、ちょっと書いてみました。
実はNTPD ST1サーバが時々固まることがあって、ワークアラウンドとしてwatchdogを使うことを思いつきました。
gonzoさんのmips/atheros/ar71xx_wdog.cを雛形にしました。
mediatekはmt7620までとこれ以降はアーキテクチャが違うようなので、v1としてmt7620までをサポートします。
FreeBSD/mipsではtimerはmips 4k共通のtimerを使っていて、SOCにはそれ以外にtimerが用意されていることが多いです。RT3050ではtimer0とtimer1があり、そのうちtimer1がwatchdogとして使える仕様になっています。
RT3050のデーターシートはネットでダウンロードできます。Timer1は0x120からあり、0がR/WのTimer設定(16bit)で4がROのTimer値で8がR/Wで設定になります。
probeとattachとwatchdog用のfnを作れば良いようです。
watchdogはタイマーを設定して有効にして、タイマーが切れる前に再設定して動きます。再設定せずにタイマーが切れるとリセットします。
普通のFreeBSDは突然リセットするのはまずいのですが、ZRouterではrootfsをroでmountしているので、いつリセットされてもOK牧場です。
呼び出しはユーザランドのwatchdogとwatchdogdがやってくれます。watchdogは単発で呼び出してwatchdogdはデーモンで定期的に呼び出します。watchdog一回実行するとしばらくするとリセットしてしまいます。watchdogdをkillで終了させると、watchdogを止めます。
ざっくりざっくり実装してみました。
sysctlで見るとこんなです。
# sysctl -a | grep wdog
dev.mtk_wdog.0.debug: 0
dev.mtk_wdog.0.%parent: palmbus0
dev.mtk_wdog.0.%pnpinfo: name=watchdog@120 compat=ralink,rt3050-wdt
dev.mtk_wdog.0.%location:
dev.mtk_wdog.0.%driver: mtk_wdog
dev.mtk_wdog.0.%desc: MTK WatchDog(Timer1) Controller (v1)
dev.mtk_wdog.%parent:
fnにはWD_INTERVALが25で飛んできますが、だいたい10秒間隔で呼ばれます。これは絶対に25秒以内には呼ぶからってことだと思われます。
watchdogで再起動した場合はresetレジスタにフラグが立ちます。
実際どれくらい進んでいるかカウンターを見てみました。初期値
0xf000に対し0xa39bになっていたので、
0xf000 - 0xa39b = 0x4c65(19557)
だいいたい1955 per 1 sec
これはおそらく
(192MHz * 2) / ( 65536 * 3 )
に近いですが、3がどっから出てくるのかは不明です。
とりあえず最大時間(0xffff)で33秒くらい待つようにしてみました。
atherosの方を試してみたのですが、watchdogdを起動するとじきにリセットされてしまいます。タイマーの設定値がまずいようです。AtherosのTimer値は32ビットで、最大値でも1分くらいみたいです。あまり厳密にタイマー値は計算せず最大値も良い気がします。
最初からwatchdogを前提にしたシステムは如何なものかと思いますが、場合によっては有効な方法かもしれません。
ただwatchdogはテストが困難なので、ご利用は計画的にお願いします。
しばらくぶりで近所の公園に行ったら、犬を連れた人が以前に比べてすごく多い気がしました。巣ごもり需要ででしょうか?
reset起因のレジスタをsysctlの値に追加してみました。
dev.mtk_wdog.0.rststat: 2
MediatekのSOCは電源ON,reboot,watchdogの区別ができます。
電源ONやwatchdogの場合は通常起動してrebootの場合はプロセスの軌道を行わないようにしました。これはリモートからrerootでflashをupdateするときに、プロセスが上がってしまうとrerootがメモリ確保に失敗してupdateが上手く出来ないためです。
AtherosのSOCはwatchdogの区別しかできないようです。