あっきぃ日誌

鉄道ブログのような技術系ブログのようななにか

Raspberry Pi Compute Module 4でPCI Expressデバイスを動かす(GbE NIC編)

Raspberry Pi Advent Calendar 2020の11日目です。

adventar.org

10日目に書いたRaspberry Pi Compute Module 4でPCI Expressバイスを動かすまでの話です。以下は前回のやつ。

akkiesoft.hatenablog.jp

さして起動してもサクッとは認識しないPCIeデバイス

前回の記事の最後にちらっと書きましたが、Raspberry PiPCI Expressが出てきたのはPi 4のUSB3.0ポート用チップ搭載からなので、そのへんの最適化しか考慮されていなければ、もちろん他のPCIeデバイス用のドライバーも標準では用意されていないので、基本的には自分でコンパイルする必要があります。また、ARM環境で使えるデバイスばかりとは行かない点にも要注意です。

なので、今回手元にあったGbE NIC10GBe NICGPUのうち、いまのところ動作させられたのはGbE NICだけという点は先に書いておきます。惜しい!

先人の資料とBARアドレス空間について

海外では、すでにCM4をゲットした人達によって動作させるための情報がまとめられ始めています。多分一番まとまっているのではないかと思うのが、Jeff Geerling氏によるページです。

pipci.jeffgeerling.com

Jeff氏のまとめ曰く、ソースコード云々やARMでコンパイルが通るかとは別に、PCIeデバイスを初期化するときに使うBARアドレス空間というものを広げるための作業が必要なケースが多いとのこと。BARアドレス空間を広げるための手順は以下に公開されています。

Increase the BAR memory address space for PCIe devices on the Raspberry Pi Compute Module 4 · GitHub

また、rpi-updateコマンドでnextブランチのファームウェアを持ってくると、最初からBARアドレス空間が拡張された状態になるとのことなので、PCIeデバイスでほげほげして遊ぶならnextブランチの最新ファームにしてしまったほうが良いかもしれません。私もdtbを書き換えたりしてみましたが、ソースコードコンパイルの方でうまく行かなかったので、最新ファームコースでやっていくことにしました。

nextブランチの最新ファームにして、カーネルソースを拾う

以下のrpi-updateコマンドで最新ファームを拾います。これをやるとファームウェア周りがdebパッケージ管理の道から逸れていくため、これ用にOSを用意したほうが良いです。

pi@raspberrypi:~ $ sudo BRANCH=next rpi-update

適用したらOSを再起動して、rpi-updateで適用されたLinuxカーネルのリビジョンと同じカーネルソースをダウンロードします。rpi-sourceというツールがあるのでこれを使ってダウンロードします。ダウンロード後は/home/pi/linuxソースコードにアクセスできます。

pi@raspberrypi:~ $ sudo apt install -y rpi-source
pi@raspberrypi:~ $ rpi-source

ドライバーをコンパイルしよう

わたしはLinuxカーネルコンパイル周りに明るくないので、menuconfigでちくちくと項目を見ていくことにします。

pi@raspberrypi:~/linux $ sudo apt install -y libncurses-dev
pi@raspberrypi:~/linux $ make menuconfig

ネットワークドライバー周りは「Device Drivers」→「Network device support」→「Ethernet driver support」にありました。手元にはHP NC320TというBroadcomチップ採用のGbE NIC(tg3が必要)と、先日会社に行った時に廃品コーナーから持ってきたIntel PRO/1000 PT Desktopアダプター(e1000eが必要)があったので、それぞれ有効にします。Intelのは3つほどあってよくわからんかったのでとりあえず全部有効化しての状態にしました。

Broadcomのドライバーは「Broadcom Tigon3 support」とわかりやすく1つだったのでこれをに変更。これで一旦.configに保存して抜けます。

コンパイルは全部やってると日が暮れる(と思いきやそうでもなさそうっぽいですが)ので、今有効にしたやつだけコンパイルしたいです。ぐぐったらどうもできそうだったので、以下の記事を参考にコンパイルしました。

blog.be-dama.com

ドライバーをコンパイルする前にmake modules_prepareを実行します。

pi@raspberrypi:~/linux $ make modules_prepare

まずはIntel。depmodに失敗してそうですが、なんか大丈夫そうです。depmodは手でやってみます。

pi@raspberrypi:~/linux $ cd drivers/net/ethernet/intel/e1000e
pi@raspberrypi:~/linux/drivers/net/ethernet/intel/e1000e $ make -C /home/pi/linux M=`pwd` -j 4
(略)
pi@raspberrypi:~/linux/drivers/net/ethernet/intel/e1000e $ sudo make -C /home/pi/linux M=`pwd` -j 4 modules_install
make: Entering directory '/home/pi/linux-f77383ec0ed313e8ab19067065b423fb3e17ab82'
  INSTALL /home/pi/linux/drivers/net/ethernet/intel/e1000e/e1000e.ko
  DEPMOD  5.10.0-rc7-v7l+
Warning: modules_install: missing 'System.map' file. Skipping depmod.
make: Leaving directory '/home/pi/linux-f77383ec0ed313e8ab19067065b423fb3e17ab82'
pi@raspberrypi:~/linux/drivers/net/ethernet/intel/e1000e $ sudo depmod -a

同様にtg3もコンパイルします。

pi@raspberrypi:~/linux $ cd drivers/net/ethernet/broadcom
pi@raspberrypi:~/linux/drivers/net/ethernet/intel/broadcom $ make -C /home/pi/linux M=`pwd` -j 4
(略)
pi@raspberrypi:~/linux/drivers/net/ethernet/intel/broadcom $ sudo make -C /home/pi/linux M=`pwd` -j 4 modules_install
make: Entering directory '/home/pi/linux-f77383ec0ed313e8ab19067065b423fb3e17ab82'
  INSTALL /home/pi/linux/drivers/net/ethernet/broadcom/tg3.ko
  DEPMOD  5.10.0-rc7-v7l+
Warning: modules_install: missing 'System.map' file. Skipping depmod.
make: Leaving directory '/home/pi/linux-f77383ec0ed313e8ab19067065b423fb3e17ab82'
pi@raspberrypi:~/linux/drivers/net/ethernet/intel/broadcom $ sudo depmod -a

コンパイルできたら、一旦電源を落として、まずはIntel PRO/1000 PT Desktopをスロットに差し込んで起動してみます。

Intel PRO/1000 PT Desktop

f:id:Akkiesoft:20201210232442j:plain

起動すると、オンボードNICのeth0と別に、eth1が生えて、IPアドレスが取得できていました。

pi@raspberrypi:~ $ ip a
(略)
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:1b:21:**:**:** brd ff:ff:ff:ff:ff:ff
    inet 192.168.29.124/24 brd 192.168.29.255 scope global dynamic noprefixroute eth1
       valid_lft 14261sec preferred_lft 12461sec

ethtoolコマンドで、eth1がIntelNICが確認します。e1000eドライバーが読み込まれているのでIntelNICですね。

pi@raspberrypi:~ $ ethtool -i eth1
driver: e1000e
version: 5.10.0-rc7-v7l+
firmware-version: 5.11-10
expansion-rom-version: 
bus-info: 0000:01:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no

LANケーブルをIntelNICだけにした状態で再起動してみても、IntelNICを使ってSSH接続ができました。

f:id:Akkiesoft:20201210232615j:plain

iperf3を動かした結果はこのとおり。概ねギガビットの性能ですね。

[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  1.02 GBytes   879 Mbits/sec                  receiver

HP NC320T

f:id:Akkiesoft:20201210233222j:plain

こちらはいきなりオンボードNICの接続無しでチャレンジ。再試しながらやっていたのでtg3ドライバーのコンパイルを忘れていてアクセスできないと焦りましたが、コンパイルして再起動したら無事に接続できました。

3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:19:bb:**:**:** brd ff:ff:ff:ff:ff:ff
    inet 192.168.29.125/24 brd 192.168.29.255 scope global dynamic noprefixroute eth1

ドライバー情報。ちゃんとtg3ドライバーで動いていますね。

pi@raspberrypi:~ $ ethtool -i eth1
driver: tg3
version: 5.10.0-rc7-v7l+
firmware-version: 5721-v3.55a
expansion-rom-version: 
bus-info: 0000:01:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no

こちらも一応iperf3で計測しました。こちらもちゃんとギガビット性能でした。

[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  1.03 GBytes   881 Mbits/sec                  receiver

まとめ

Raspberry Pi Compute Module 4で、まずはGbE NIC2種類を動作させてみました。GbE NICはCM4本体に載っているので、わざわざPCIeデバイスで生やす必要がなく、動いても有りがたみは薄いのですが、普段PCやらサーバーに挿せば何も考えなくてもサクッと認識するメジャーすぎるデバイスをドライバーのコンパイルからやっていくというのは、なんというか大事なことだなあと思うなどしました。

さて、次は10GbE NIC、次はGPU、とポンポンいきたいところですが、どちらもいまのところうまくいっていないので、このへんが明日の記事になることはありません。残念。

他に手持ちのPCIeカードがそんなにないのであれですが、NVMe SSD変換あたりはちょっと用意できる状況になったので、明日はそのへんのチャレンジと記事化……までできるといいなと思っています。