2008年1月9日水曜日

NetBSDでWatchdog timerを使う(CS5535/CS5536)

ちょっと前にNetBSDでWatchdog timerを使う(for ALIX) (1) という一連のエントリーを書いたけれど、年が明けたころからNetBSD-currentへの統合作業をやっていた。手元にあるALIXでは普通に動くのだけど、ほかのボードではどうもうまく動かない(watchdog timerをenableすると一瞬でリブートされてしまう)と言うレポートが担当となったcommiterの人からあがってきてその理由を追ってみたので、メモがてらに何が起こっていたかを書いてみることにする。

  • 元々のコードの仮定:CS5536のMFGPT0はNetBSD kernel以外では使っていない。だから、watchdog timer用のtimerとしてMFGPT0を決めうちで使っても問題無い
動かないといわれても動かないボードは手元に無いので、debugの出力をてんこ盛りにしたテスト用のドライバをつくって、何回かやりとりをしてみた。その結果
  • 何者かがNetBSD kernelがアクセスする前に、MFGPT0を設定して(たぶん、何かの用途に使って)いる。
ことがわかった。MFGPTのsetupレジスタはほとんどのビットフィールドがwrite onceレジスタになっていて、一度設定されるとリセットするまで再設定はできない設計になっている。だから誰かが設定してしまうと、その後は必要な設定を上書きすることができないので事実上watchdog timerとしては利用できない。特に問題なのはタイマーの分周器の設定で、分周比が低すぎるとあっというまにタイマーがまわってしまって、watchdogが動く値に到達してしまう、というのがリブートされる理由だった。たぶん問題になったボードではBIOSなどが何かの用途に設定してしまっているのではないかと推測している。

この問題に対応するためにやったことは、
  • gcscpcib_attach()のwatchdog timerを設定するところで、gcscpcib_scan_mfgpt()という関数(とりあえず書いた)を使って、その時点で使われていないMFGPTを探して使うことにした
  • 必要なら決めうちで利用するMFGPTを指定できるようにした
というあたり。更にマージする前に、もう少しお行儀の良いコードにしようと思って
  • MFGPT関連のレジスタの更新ロジックを、仕様書に指定されている「前準備」−「更新」-「後始末」というシーケンスでやるようにした。
前準備ではカウンタを止めたり、割り込みを禁止したりする必要があり、後始末では関連フラグをクリアしたりしなければならないらしい。手元のALIXではそんなことをしなくても動いていたんだけど、debugする過程で書いてしまったので正式採用した。更に
  • watchdogの間隔を最低値(1秒)にすると運が悪い時にリブートしちゃう問題、が起こらないようにタイマーの精度を1Hzから4Hzにあげた。
  • define一つでタイマーの精度を指定できるようにした
  • まともなdebug messageを埋めた
あたりを入れ込んだ。

元々はAMD CS5536用のコードとしてsend-prしたが、CS5536とCS5535はほとんど一緒、ということもあって共用のドライバーとして扱うことにした。で、名前もOpenBSDのglxpcibからgcscpcibという名前に変更。

というわけでHEADにマージされました。cvswebでは明日以降ならみえるんじゃないかな。

0 件のコメント: