« 年末年始の発送 | トップページ | LinuxでのCombined Write »

2017.01.06

PCI ExpressのFPGAを効率的に開発する方法(Linux版)

PCI ExpressをFPGAで実装すると、新しいデザインが出来たら当然、書き換えることになります。

FPGAを書き換えると内部のレジスタがすべて0にクリアされてしまいます。BARなどの設定値が全部消えてしまうので、アクセスできなくなってしまいます。

普通はFPGAを書き換えるたびにOSを再起動しなければなりません。再起動を待つ時間がもったいないだけでなく、アプリの起動やディレクトリの移動など面倒な手間が増えます。

PCI ExpressのFPGAを書き換えても、OSの再起動なしに続行したいわけです。

Windowsの場合ならばデバイスマネージャから無効/有効を行えばBARの再設定が行われるので再起動する手間を省けますが、Linuxでやる方法を調べました。

ここではScientific Linux CERN 6 (SLC6)というディストリビューションを使用しています。

sun

基本的なやり方は、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で表示される一覧の一番左の数字です。

Lspci

上のDPIO moduleというのがFPGAで作ったPCI Expressのファンクションです。この数字が4なので、rescan 4とすると、上のスクリプトが起動して、PCI Expressデバイスが削除されてから再スキャンされて、BARが再設定されるというわけです。

これで、OSを再起動することなく、FPGAのみ書き換えて動作を続行することができるようになります。

sun

実際にやってみてわかった注意点がいくつかあります。

  1. BARのサイズを増やすと、再設定が行われない場合がある。
    つまり、最初は16kB程度の領域を確保していて、再スキャン後に64MBに増えているような場合は、うまくいかない。FPGAを書き換えてもリクエストするメモリ空間のサイズは変えない方が良い。
  2. BARサイズを減らすのは大丈夫なようだ。
  3. 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のアドインカードを開発する人の助けになれば幸いです。

|

« 年末年始の発送 | トップページ | LinuxでのCombined Write »

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



« 年末年始の発送 | トップページ | LinuxでのCombined Write »