MIPSにはR4000(1991年)の頃からマルチCPUの対応があり、SOCでもマルチコアのものがあります。
FreeBSD/mipsアーキテクチャの場合、core間割り込み(Inter Processor Interrupt:IPI)をソフトウエア割り込みの2本のどちらかか、ハード割り込みのクロックを除く5本のどれかで行うことができるようです。
まずSMPオプションを追加してカーネルをビルドします。
必要な関数を入れたファイルを追加します。
カーネルを起動するとmips/mips/mp_machdep.cのcpu_mp_start()->start_ap()がよばれてセカンダリーのCPUが起動されます。
start_ap()はCPUごとに作られたplatform_start_ap()をよびます。
platform_start_ap()では初期化をしてセカンダリーのCPUを上げてmips/mips/mpboot.Sのmpentryに飛ばします。mpentryはmp_machdep.cのsmp_init_secondary()をよんで待機状態になります。
デバイスのコンフィグレーションが終ると待機状態を抜けてスケジューラに組み込まれます。
BCM338Xを対応させるためにlinux方面のコードを見てみます。
BCM338XはBCM63XXとほぼほぼ同等のよう。だた細かくいじられてるので、違うところがあるのかもしれない。
Broadcomが書いたもの(smp-brcm.c)と、Linux本家にコントリビュートされたもの(smp-bmips.c)は違っていて、Broadcomの方がシンブルに書かれているので、そちらを参考にします。
セカンダリーの起動はsmp-brcm.cの中でinstall_smp_boot_ex_handler()で例外ハンドラをメモリ(0x80000200)に書き込んでおいて、ソフトウエア割り込み0を上げて起動しているようです。書きこみ時はキャッシュされないように0xa0000200に書き込みします。
Linux方面のコードを見るとIPIは1本でやるケースと2本でやるケースがあるようだ。また割り込みの振り分けはプロセッサー毎の機能で処理されてるようだ。
BroadcomのソースでBMIPS4350対応したコードがsmp.cというファイルでありました。Linuxに入ってるのはこちらを参考にしたものと思われます。
BCM3383はBCM3380とは仕様が変わっているようです。
BCM3383もデフォルトではBCM3380と同じ仕様で動いてるようです。この仕様はソフトウエア割り込みを2本使い交互に割り込みが上がるようにルーティングされています。これだと2CPUまでしかサポートできないのでBCM3383では新しい仕様がサポートされたのではないかと思われます。
platform_processor_id()はCOP0のBroadcom拡張($22)にありそうなのですが、わからなかったので3の31ビット目がboot cpuを示すようなのでそれで判断しました。これだと2CPUしか対応できません。:(
Linuxにはsmp_processor_id()という関数があるのですが、どこで処理されているものなのかわかりません。
IPIはCPU0で割り込み上げてCPU1で拾えるのとこれの逆ができればいいのだと思うが。処理の中身はFreeBSD側にあるのだと思う。
FreeBSD/mipsでは相手のCPU構造体のpc_pending_ipisに命令を入れて、割り込みを上げて、割り込みが入ったCPUはその命令を拾って処理をします。
とりあえずBCM3380の機能で実装してBCM3383で確認したのですが、動きません。IPIは動いているのですがpc_pending_ipisが渡らないようです。SOC固有のキャッシュの制御が必要なのかもしれません。(2024/06/27)
オリジナルのコードがソフトウエア割り込み1本で書かれていたので、同じにしてみましたが動きません。(2025/01/27)
BCMの設定でI,Dキャッシュを有効にしないとSMPは動くのですが、むちゃくちゃ遅いです。
mp_machdep.cを逆アセンブラしてみました。ll/scでatomicな処理になっています。
00000398 <ipi_send>:
398: c0820078 ll v0,120(a0)
39c: 00a21025 or v0,a1,v0
3a0: e0820078 sc v0,120(a0)
3a4: 1040fffc beqz v0,398 <ipi_send>
3a8: 00000000 nop
3ac: 08000000 j 0 <cpu_mp_announce>
3b0: 8c840024 lw a0,36(a0)
CP0_BCM_CFG_DCSHENを設定しないととっても遅いですがloginまで進めます。ただタイマーが狂ってしまうみたいで、300秒が一瞬でカウントされloginできません。(2025/2)