現在のデバイスコンフィグレーションの仕組みは以下の四つがあります。
- ハードコードからのコンフィグレーション
- hintsによるコンフィグレーション
- fdtによるコンフィグレーション
- kldloadによるロード
ハードコードからのコンフィグレーションは親のデバイスのコードでのBUS_ADD_CHILD()メソッドにより実行されます。
hintsによるコンフィグレーションはbuildkernelでカーネル内に放り込まれたhintsの情報により読み込みが実行されます。BUS_ADD_CHILDで読み込まれているにも関わらずhintsでも指定するとカーネルが落ちます。
hint.spi.0.at="nexus0"
hint.spi.0.maddr=0x1f000000
hint.spi.0.msize=0x10
fdtによるコンフィグレーションはbootから引き渡されたdtbかbuildkernel時にスタティックに放り込まれたdtsをコンパイルしたdtbにより読み込まれます。
spi0@84000 {
compatible = "lpc,spi";
reg = <0x84000 0x4000>;
interrupts = <20>;
interrupt-parent = <&PIC>;
};
kldloadでのロードはコンフィグレーションではないですが、デバイスがコンフィグレーション同様に読み込まれます。
FreeBSDのブロジェクとの方針としてはfdtが一番推奨で、hintsが次で、おそらハードコードはあまり推奨されていないとおもいます。2016/03現在sys/armはfdtに移行していますがsys/mipsはあまりftdへの移行が進んでいませんが、少しずつコードは入ってきています。
子と親の関係は、ドラーバーコードのDRIVER_MODULEで定義されています。これはhintsベースでもFDTベースでも同じです。EARLY_DRIVER_MODULEで定義された物は先にロードされます。
FreeBSDの現在のデバイスのコンフィグレーションの問題として、デバイスのロードされる順番が明示的に設定できないケースがあります。デバイスがバスの場合、マイナー番号が変わってしまうと子になるデバイスが正しくロードできない可能性があります。
spiバスのmx25lがあるmipsなルータでgpiospiを追加したところgpiospiがspibus0になりhintsでspibus0としたmx25lが見えなくなる事がありました。現在のFreeBSDでは細かい順番が設定できないためmx25lのhintsをspibus1と書き換えるしかないです。
コンソール
コンソールはデバイスがコンフィグレーションされる前に使用されるため上のコンフィグレーションとは別にコンソール用のコンフィグレーションで初期化されます。
コンソールはOSのソース内でCONSOLE_DRIVERで登録されたドライバの中でスコアの高いものをコンソールに選びます。シリアルコンソールの場合dev/uart/uart_tty.cに登録がありこれを使います。実体はuart_cpu_getdev()で取得するようになっています。
uart_cpu_fdt.cではdtsファイルの"/chosen"のデバイスか"serial0"なデバイスが選択されるようです。そのデバイスのcompatibleがofw_compat_dataにあるソースのクラスが利用されます。
/sbin/initが起動されるまではコンソールドライバに出力され、init起動後はbusなuartが使われるようになります。コンソールへの出力ではFIFOが空になったという割り込みは使われません。これはシステム起動後には割り込みコントローラが(PIC)を処理するデバイスが登録されていない状態のためです。
リソースと割り込み
FreeBSDでは古来からのprobe(),attach()を使ってデバイスのコンフィグレーションを行いますが、リソースの確保はbus_alloc_resource_any()で行われます。割り込みのハンドラの登録はbus_setup_intr()で行います。FreeBSDの割り込みハンドラは二つあり、filterとithreadと呼ばれています。
二つに分けているのは割り込みの処理があまり大きくなって、パフォーマンスに影響するのを避けるためではないかと思われます。
INTRNG
armのプロジェクトの成果のINTRNGが他のアーキテクチャでも使えるようになりました。INTRNGの目標はirq処理の整理とPICとBUSの分離またマルチプロセッサー上での最適化と思われます。
bus_setup_intr()は変えずにその中で処理される仕組みを変えています。
armはv4系ではハードウエア割り込みが1本ですが、v6以降では複数あるようです。
armv5tなRT1310の割り込みは以下のようになっています。
mipsなar5315の割り込みは以下のようになっています。6本の割り込みはMIPS共通です。PICはそれぞれのSOC毎に違います。INTRNGではMIPS共通の割り込みの登録はcpu_establish_hardintrでおこないます。
mips 4KではTimerが固定で用意されています。これ以外はボード毎に違っています。
BCM4712はPICはなくてMIPSの6本の割り込みだけになっている。0-4の割り込みに複数の割り込みをアサイン出来るようだ。
mips/mediatek(RT3050)のkern/subr_intr.cのデバッグログ
intr_pic_register(): PIC 0x805acdc0 registered for cpupic0 <dev 0x80554100, xref 3>
intr_pic_claim_root(): irq root set to cpupic0
intr_pic_register(): PIC 0x805ac080 registered for intc0 <dev 0x80553800, xref 1>
intr_setup_irq(): irq 2 add handler error 0 on intc0
intr_pic_register(): PIC 0x805abdc0 registered for gpio0 <dev 0x80553680, xref 9>
intr_setup_irq(): irq 14 add handler error 0 on gpio0
intr_setup_irq(): irq 20 add handler error 0 on uart0
intr_setup_irq(): irq 5 add handler error 0 on rt0
intr_setup_irq(): irq 7 add handler error 0 on cpupic0
subr_intr.cの中には同じpanicに同じメッセージのところがあり、どこで落ちたのかわかりません。なんともいけてないです。
subr_intr.cのirq_mapは4Kの割り込みは全部登録されていますが、PICは割り込みがあるものだけ登録するようです。