Linux Kernel 4.10 でのFPGAのサポート事情

# はじめに



## 経緯


次の記事で Linux Kernel 4.4 から FPGA Manager Framework が提供されるようになったことを紹介しました。またこれらの記事で、4.4 では Higher Level Interface が提供されていないので、ユーザーがカーネルドライバを書かなくてはならないこと、簡易的かつ実験的な意味で fpgacfg ドライバを作ったこと、またその後の状況を説明しました。



* [「FPGA+SoC+Linux で FPGA Manager を試してみた」 @Qiita](http://qiita.com/ikwzm/items/9eb4d49545636162057e)
* [「FPGA+SoC+Linux で FPGA Manager を試してみた(まとめ)」 @Qiita](http://qiita.com/ikwzm/items/393d483131bcf6ad7cb0)
* [「FPGA+SoC+Linux で FPGA Manager を試してみた(まとめ2)」 @Qiita](http://qiita.com/ikwzm/items/4f89cf7cb42f6cc2705f)



Linux Kernel 4.10 になり、ようやく FPGA Manager Framework の Higher Level Interface が提供されるようになりました。その名も FPGA Region です。この記事ではその FPGA Region  について説明します。




## FPGA Region とは


一言でいえば、Linux FPGA Manager Framework の Higher Level Interface です。つまり、ユーザーは FPGA Region に指示を出すことにより、FPGA へのプログラムの書き込みや起動を行います。



具体的には Linux Kernel 内では次の図ような構造になっています。


![Fig.1 Linux Kernel 4.10 の FPGA デバイスドライバの構成](https://qiita-image-store.s3.amazonaws.com/0/24981/1faffe27-d794-6359-fcbe-21d574e88bca.jpeg)

Fig.1 Linux Kernel 4.10 の FPGA デバイスドライバの構成

<br />



Fig.1 のシェードのかかった部分が FPGA Reagion です。その下の FPGA Manager Framework とその Low Level FPGA Driver が Linux Kernel 4.4 で追加されたところで、FPGA Region はその上位に位置しています。

また、Linux Kernel 4.10 から新たに FPGA Bridge Framework が追加されています。これは FPGA のコンフィギュレーション時にFPGA(PL部)ーCPU(PS部)間のインターフェースを無効(切断)したり起動時に有効(接続)するための機能を提供するフレームワークです。

FPGA Region は、FPGA Manager Framework と FPGA Bridge Framework を管理しています。 

さらにこの FPGA Region は FPGA の Partial Reconfiguration にも対応しています。それ故に Region というちょっと意味不明な名称がつけられたのかもしれません(Region という言葉は Paritial Reconfiguration でよく使われます)。


# FPGA Region の使い方



## Linux Kernel のビルド


私が FPGA Region の動作を確認した Linux Kernel のバージョンは 4.12.2 です。通常は FPGA Region、FPGA Manager Framework、FPGA Bridge Framework はオフになっていて組み込まれません。これらのオプションをオンにして Linux Kernel をビルドしておく必要があります。

具体的には make menuconfig で次の項目をオンにします。

*  Device Drivers ---> FPGA Configuration Support --->

  * FPGA Configuration Framework
  * FPGA Region
  * FPGA Bridge Framework

または .config に以下の行を追加します。

  * CONFIG_FPGA=y
  * CONFIG_FPGA_REGION=y
  * CONFIG_FPGA_BRIDGE=y 

また使用する FPGA にあわせて Low Level FPGA Driver も組み込む必要があります。



Zynq の場合は、 make menuconfig で次の項目をオンにします。

*  Device Drivers ---> FPGA Configuration Support --->

  * Xilinx Zynq FPGA
  * Xilinx LogiCORE PR Decoupler

または .config に以下の行を追加します。

  * CONFIG_FPGA_MGR_ZYNQ_FPGA=y
  * CONFIG_XILINX_PR_DECOUPLER=y



Altera-SoC の場合は、make menuconfig で次の項目をオンにします。

* Device Drivers ---> FPGA Configuration Support --->

  * Altera SOCFPGA FPGA Manager
  * Altera SoCFPGA FPGA Bridge
  * Altera FPGA Freeze Bridge
  * Altera Partial Reconfiguration IP Core
  * Platform support of Altera Partial Reconfiguration IP Core

または .config に以下の行を追加します。

  * CONFIG_FPGA_MGR_SOCFPGA=y 
  * CONFIG_SOCFPGA_FPGA_BRIDGE=y
  * CONFIG_ALTERA_FREEZE_BRIDGE=y
  * CONFIG_ALTERA_PR_IP_CORE=y
  * CONFIG_ALTERA_PR_IP_CORE_PLAT=y


## Device Tree へ追加(Zynq)


Zynq の場合は、Linux 起動時に使用する Device Tree に以下の項目を追加しておきます。


```devicetree:zynq-zybo.dts

/dts-v1/;
/ {
	:
	(中略)
	:
	amba {
		devcfg: devcfg@f8007000 {
			compatible = "xlnx,zynq-devcfg-1.0";
			reg = <0xf8007000 0x100>;
			interrupt-parent = <&intc>;
			interrupts = <0 8 4>;
			clocks = <&clkc 12>;
			clock-names = "ref_clk";
			syscon = <&slcr>;
		};
		fpga_region0: fpga-region0 {
			compatible = "fpga-region";
			fpga-mgr = <&devcfg>;
			#address-cells = <1>;
			#size-cells = <1>;
			ranges;
		};
	:
	(後略)
	:
```



devcfg は Zynq 用の FPGA Manager の Low level Driver です。fpga_region0 の fpga-mgr に FPGA Manager の Low level Driver のハンドル値かシンボルを指定します。例では devcfg のシンボルを指定しています。

Zynq の場合は FPGA(PL部)-CPU(PS部)のブリッジの制御は devcfg が行うので、FPGA Bridge Framework は指定しません。




## Device Treeへの追加(Altera-SoC)


Altera-SoC の場合は、Linux 起動時に使用する Device Treeに以下の項目を追加しておきます。

```devicetree:socfpga.dts
/dts-v1/;
/ {
	:
	(中略)
	:
	soc {
		:
		(中略)
		:
		fpga_bridge_lwhps2fpga: fpga_bridge@ff400000 {
			compatible = "altr,socfpga-lwhps2fpga-bridge";
			reg = <0xff400000 0x100000>;
			resets = <&rst LWHPS2FPGA_RESET>;
			clocks = <&l4_main_clk>;
			bridge-enable = <0>;
		};

		fpga_bridge_hps2fpga: fpga_bridge@ff500000 {
			compatible = "altr,socfpga-hps2fpga-bridge";
			reg = <0xff500000 0x10000>;
			resets = <&rst HPS2FPGA_RESET>;
			clocks = <&l4_main_clk>;
			bridge-enable = <1>;
		};

		fpga_bridge_fpga2hps: fpga_bridge@ff600000 {
			compatible = "altr,socfpga-fpga2hps-bridge";
			reg = <0xff600000 0x10000>;
			resets = <&rst FPGA2HPS_RESET>;
			clocks = <&l4_main_clk>;
		};

		fpgamgr0: fpgamgr@ff706000 {
			compatible = "altr,socfpga-fpga-mgr";
			reg = <0xff706000 0x1000
			       0xffb90000 0x4>;
			interrupts = <0 175 4>;
		};

		fpga_region0: fpga-region0 {
			compatible = "fpga-region";
			fpga-mgr = <&fpgamgr0>;
			fpga-bridges = <&fpga_bridge_lwhps2fpga &fpga_bridge_hps2fpga &fpga_bridge_fpga2hps>;
			#address-cells = <0x1>;
			#size-cells = <0x1>;
			ranges;
		};
	:
	(後略)
	:
```

```fpga-mgr = <&fpgamgr0>;``` で fpga-mgr に Altera-SoC用の FPGA Manager の Low level Driver である fpgamgr0 を指定しています。
```fpga-bridges = <&fpga_bridge_lwhps2fpga &fpga_bridge_hps2fpga &fpga_bridge_fpga2hps>;``` で 管理下に置く FPGA-Bridge を指定しています。



## FPGA のコンフィギュレーション


Linux Kernel に組み込んだ FPGA Region を使って FPGA のコンフィギュレーションを行うには、Device Tree を使います。そのため、Linux Kernel 起動後にFPGA のコンフィギュレーションを行うには、Device Tree Overlay が必要です。

例えば、Zynq 用に sample.bin というビットストリームファイルを作ったとして、それを FPGA にコンフィギュレーションするためには、次のような Device Tree を用意します。


```devicetree:sample.dts
/dts-v1/; /plugin/;
/ {
	fragment@1 {
		target-path = "/amba/fpga-region0";
		#address-cells = <1>;
		#size-cells = <1>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <1>;
			firmware-name = "sample.bin";
		};
	};
};
```


target-path に Linux Kernel に組み込んだ FPGA Region の絶対パスを指定します。この例では Zynq 用に /amba の下に fpga-region0 という名前で FPGA Region を組み込んだので /amba/fpga-region0 を指定しています。

また、target-path=パス名; ではなく target=\<&fpga_region0\>; のようにハンドル値またはシンボルで指定することもできます。

firmware-name = ファイル名; として FPGA にコンフィギュレーションしたいビットストリームファイルの名前を指定します。ただし、ビットストリームファイルは /lib/firmware の下になければなりません。

Altera-SoC ではビットストリームファイルは rbf 形式でなければなりません。

 Zynq の場合は注意が必要で、なぜか Vivado が生成したビットストリームファイルは、そのままでは使えません。32ビット(4バイト)内でバイト位置をスワップしておく必要があります。ツールは[「Linux の FPGA Manager で Xilinx のビットストリームファイルを扱う方法」](http://qiita.com/ikwzm/items/1bb63be0b86a1e0e56fa)で紹介しています。


Device Tree Overlay でシンボルを使う場合は、 Device Tree Compiler がサポートしている必要があります。古い Device Tree Compiler では使えないことがあるので注意してください。詳しくは[「デバイスツリーにシンボル情報を埋め込む」](http://qiita.com/ikwzm/items/03d518b7c46d1ee49943)を参照してください。


# 所感


Linux Kernel 4.4 で FPGA Manager Framework が実装されてから待望の Higher Level Interface である FPGA Region ですが、まだまだ問題点や疑問点もあります。ここでは私が個人的に感じた FPGA Region のイケてない点やモヤモヤしている点を挙げます。あくまでも現状の話であり今後は解決されることを望みます。




## Device Tree に過度に依存している


前節で説明したとおり、FPGA Region を使うためには Device Tree が必要です。しかしもともと Device Tree 自体は特定のプロセッサ(ありていに言えばARM)用のデバイスドライバがポータビリティに問題点がありすぎて Linus Torvalds 氏の怒りに触れて導入された経緯があり、x86 系のCPU ユーザーには馴染みがありません。今はまだ FPGA+SoC+Linux では ARM が使われていることが多いので構いませんが、将来にわたって Device Tree を使い続けていくのか？という疑問が残ります。




## Device Tree Overlay の正式サポートがまだない


FPGA は動的にコンフィギュレーション出来るのが「売り」の一つですが、FPGA Region でLinux 起動後に FPGA のコンフィギュレーションを行うためには Device Tree Overlay が必須です。ところが、何故か Device Tree Overlay をユーザーから行うための機能が Linux では正式にサポートされていません。現状はカーネルのドライバを作るか、あるいは dtbocfg のように私が簡易的にでっちあげたドライバを使う必要があります。Device Tree Overlay と dtbocfg の関しては[「FPGA+SoC+Linux で Device Tree Overlay を試してみた」](http://qiita.com/ikwzm/items/ec514e955c16076327ce)を参照してください。




## クロックの制御が中途半端


FPGA を動かすにはクロックの制御が必要です。出来れば動的に周波数を変えたり、コンフィギュレーション中や動作していないときはクロックを止めたりしたいところですが、残念ながら FPGA Region ではクロックの制御が規定されていません。別にドライバが必要か、あるいは FPGA Manager/Bridge Framework の  Low level Driver でこっそり制御しているのが実情です。




## Xilinx のビットストリームファイルを直接扱えない


「FPGA のコンフィギュレーション」でも述べましたが、現状、なぜか Vivado が生成したビットストリームファイルは、そのままでは使えません。何故こんなことになったのか理解に苦しみますが、どうにかしてほしいところです。




## そもそもカーネルに組み込む必要があるのか


FPGA Region はハードウェアを直接制御していません。やっていることは、下位のドライバ(FPGA Manager や FPGA Bridge など)の管理です。ですからわざわざ Linux の Kernel に組み込む必要があるとは思えません。むしろ Low Level Driver 各自にユーザー空間から制御できるインターフェース(API)を設けて、このようなフレームワークはユーザー空間でやったほうが、メンテナンスの事も考えると良い気がします。ユーザー空間でならば C言語でなく、Python のようなより生産性の高い言語が使えます。




# 参考


* [「[Linux][kernel] Device Tree についてのまとめ」 @Qiita](http://qiita.com/koara-local/items/ed99a7b96a0ca252fc4e)
* [「FPGA+SoC+Linux で FPGA Manager を試してみた」 @Qiita](http://qiita.com/ikwzm/items/9eb4d49545636162057e)
* [「FPGA+SoC+Linux で FPGA Manager を試してみた(まとめ)」 @Qiita](http://qiita.com/ikwzm/items/393d483131bcf6ad7cb0)
* [「FPGA+SoC+Linux で FPGA Manager を試してみた(まとめ2)」 @Qiita](http://qiita.com/ikwzm/items/4f89cf7cb42f6cc2705f)
* [「FPGA+SoC+LinuxでDevice Tree Overlayを試してみた」 @Qiita](http://qiita.com/ikwzm/items/ec514e955c16076327ce)
* [「デバイスツリーにシンボル情報を埋め込む」 @Qiita](http://qiita.com/ikwzm/items/03d518b7c46d1ee49943)
* [「Linux の FPGA Manager で Xilinx のビットストリームファイルを扱う方法」 @Qiita](http://qiita.com/ikwzm/items/1bb63be0b86a1e0e56fa)