PCI ExpressのFPGAを効率的に開発する方法(Linux版)
PCI ExpressをFPGAで実装すると、新しいデザインが出来たら当然、書き換えることになります。
FPGAを書き換えると内部のレジスタがすべて0にクリアされてしまいます。BARなどの設定値が全部消えてしまうので、アクセスできなくなってしまいます。
普通はFPGAを書き換えるたびにOSを再起動しなければなりません。再起動を待つ時間がもったいないだけでなく、アプリの起動やディレクトリの移動など面倒な手間が増えます。
PCI ExpressのFPGAを書き換えても、OSの再起動なしに続行したいわけです。
Windowsの場合ならばデバイスマネージャから無効/有効を行えばBARの再設定が行われるので再起動する手間を省けますが、Linuxでやる方法を調べました。
ここではScientific Linux CERN 6 (SLC6)というディストリビューションを使用しています。
![]()
基本的なやり方は、rescanというドライバを使って、
sudo echo "1" > /sys/bus/pci/rescan
のようにします。一瞬、??となる書き方なのですが、rescanというのは、
--w--w---- 1 root root 4096 1月 6 16:09 2017 /sys/bus/pci/rescan
というスペシャルファイルで、このファイルに1を書き込むと再スキャンが行われるという代物のようです。
ただ、私が使っているSLC6というディストリビューションではrescanに書くだけではうまく行かず、sudoを付けていても許可がありませんと出てしまいます。
そこでchmod 666でドライバrescanに読み書き属性を付与してから行っています。また、なぜかrescanだけではうまくいかないので、removeというドライバにも同様に1を書き込んでから行います。
結局のところ、以下のようなスクリプトを書いて実行しています。
#!/bin/sh sudo chmod 666 /sys/bus/pci/devices/0000\:0$1\:00.0/remove sudo echo 1 > /sys/bus/pci/devices/0000\:0$1\:00.0/remove sudo chmod 666 /sys/bus/pci/rescan sudo echo "1" > /sys/bus/pci/rescan
使い方は、./rescan 4 のようにrescanの後にバス番号を指定します。
バス番号というのは、lspciで表示される一覧の一番左の数字です。
上のDPIO moduleというのがFPGAで作ったPCI Expressのファンクションです。この数字が4なので、rescan 4とすると、上のスクリプトが起動して、PCI Expressデバイスが削除されてから再スキャンされて、BARが再設定されるというわけです。
これで、OSを再起動することなく、FPGAのみ書き換えて動作を続行することができるようになります。
![]()
実際にやってみてわかった注意点がいくつかあります。
- BARのサイズを増やすと、再設定が行われない場合がある。
つまり、最初は16kB程度の領域を確保していて、再スキャン後に64MBに増えているような場合は、うまくいかない。FPGAを書き換えてもリクエストするメモリ空間のサイズは変えない方が良い。 - BARサイズを減らすのは大丈夫なようだ。
- VIDやDIDが変わるのはOK。
以下に、実際の実行結果を示します。
まずは、起動したLinuxを直後にlspciでデバイスのコンフィギュレーション情報を見たところです。1bc8:1080のデバイスが見えています。Region 0..2の表示にも注目してください。
[user@px ~]$ lspci -d 1bc8:* -vvvx
04:00.0 DPIO module: Device 1bc8:1080
Subsystem: Device 1bc8:1080
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 256 bytes
Interrupt: pin A routed to IRQ 11
Region 0: Memory at dbfec000 (32-bit, non-prefetchable) [size=16K]
Region 1: Memory at dbff0000 (32-bit, non-prefetchable) [size=64K]
Region 2: Memory at dc000000 (32-bit, non-prefetchable) [size=64M]
Capabilities: <access denied>
00: c8 1b 80 10 07 00 10 00 00 00 00 11 40 00 00 00
10: 00 c0 fe db 00 00 ff db 00 00 00 dc 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 c8 1b 80 10
30: 00 00 00 00 40 00 00 00 00 00 00 00 0b 01 00 00
FPGAを書き換え中にlsmodしてみました。すべてのレジスタがffになって見えないことがわかります。
[user@px ~]$ lspci -d 1bc8:* -vvvx 04:00.0 DPIO module: Device 1bc8:1080 (rev ff) (prog-if ff) !!! Unknown header type 7f 00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 10: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
下の表示はFPGAの書き換えが完了した直後の状態です。Region 0,1,2がvirtualと出ています。
[user@px ~]$ lspci -d 1bc8:* -vvvx
04:00.0 DPIO module: Device 1bc8:1080
Subsystem: Device 1bc8:1080
Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin A routed to IRQ 255
Region 0: [virtual] Memory at fb310000 (32-bit, non-prefetchable) [size=16K]
Region 1: [virtual] Memory at fb300000 (32-bit, non-prefetchable) [size=64K]
Region 2: [virtual] Memory at fb400000 (32-bit, non-prefetchable) [size=4M]
Capabilities: <access denied>
00: c8 1b 80 10 00 00 10 00 00 00 00 11 00 00 00 00
10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 c8 1b 80 10
30: 00 00 00 00 40 00 00 00 00 00 00 00 ff 01 00 00
ここでrescanすると、
[user@px ~]$ lspci -d 1bc8:* -vvvx
04:00.0 DPIO module: Device 1bc8:1080
Subsystem: Device 1bc8:1080
Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin A routed to IRQ 255
Region 0: Memory at fb310000 (32-bit, non-prefetchable) [disabled] [size=16K]
Region 1: Memory at fb300000 (32-bit, non-prefetchable) [disabled] [size=64K]
Region 2: Memory at fb400000 (32-bit, non-prefetchable) [disabled] [size=4M]
Capabilities: <access denied>
00: c8 1b 80 10 00 00 10 00 00 00 00 11 00 00 00 00
10: 00 00 31 fb 00 00 30 fb 00 00 40 fb 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 c8 1b 80 10
30: 00 00 00 00 40 00 00 00 00 00 00 00 ff 01 00 00
virtualと表示されていたregionが設定され、使用できるようになります。
この情報が、Linux上で動くPCI Expressのアドインカードを開発する人の助けになれば幸いです。
| 固定リンク



コメント
今更の話かもですが、 sudo しても > の部分はユーザ権限で実行されるので書き込みはできないです。裏技的にteeコマンドを使って echo 1 | sudo tee /sys/bus..../reset とやるとsudoでできるようになります。お試しください。
投稿: | 2019.02.28 17:25
再スキャンをしても
割り込み番号は割り当てられないようですね
投稿: はた | 2021.07.07 14:07
割り込み番号は再割り当てされませんでしたか。
割り込みは使えなかったですか?
投稿: なひたふ | 2021.07.16 02:04