PCIeに乗せるXilinx FPGAのBRAMとのDMA通信のサンプルを動かす

自分用メモ。

丁寧にやる場合は以下のリンク先を参照してください。

https://www.xilinx.com/products/intellectual-property/pcie-dma.html

https://github.com/Xilinx/dma_ip_drivers/tree/master/XDMA/linux-kernel

https://indico.iist.nias.ac.jp/event/216/contributions/696/attachments/532/1564/20-03-osana.pdf

### 要約

自作ipを試す前段階として、Alveo 280上にVivado使ってxdma controllerとBRAM置いて、ホスト（Linux）から叩くサンプルを動かした。

### 環境

|項目|概要|
|:-:|:--|
| Linux Distribution | CentOS Linux release 7.9.2009 (Core) |
| Linux Kernel | 3.10.0-1160.45.1.el7.x86_64 |
| FPGA Board | Alveo u280 |
| Vivado | 2021.1 |


### Vivadoでやること

#### プロジェクト作成
ボード選ぶだけ、特記なし。

#### Blockデザイン

[Create Block Design]で作っていく。
[Board] > [Miscellaneous] > [PCI Express]を選択し、[DMA/Bridge Subsystem for PCI Express]を選択し、[OK]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214706/fa59b113-24cd-cbdc-7d6c-89f76f94b8b5.png)

DMAのブロックが出たら[Run Block Automation]をクリックし、今回がデフォルトで[OK]をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214706/453d9372-9b3f-57d0-846b-f1e8dce9a1c6.png)

こんな感じになる。

[Add IP]で[AXI BRAM Controller]と[Block Memory Generator]を追加。
[AXI BRAM Controller]をダブルクリックして、[BRAM Options]の[Number of BRAM interfaces]を1に変更し、[OK]。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214706/7c592726-bf9c-3c8a-f061-657f5afa491d.png)

終わったら[Run Connection Automation]。
[AXI SmartConnect]が追加されてこんな感じになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214706/e0d9071e-609b-a26b-2282-4ab685564fae.png)

#### ホストからアクセスするアドレスを変更

上部の[Address Editor]をクリック。
[/axi_bram_ctrl_0/S_AXI]の[Master Base Address]を

[ 0x0000_C000_0000 ]
[ 0x0000_<font color="red">0</font>000_0000 ]

に変更。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214706/552266f5-e300-bd27-68eb-7d78a0940ca0.png)

後は[Create HDL Wrapper]して[Generate Bitstream]。
終わったら[Open Hardware Manager]して書き込み。

書き込みが終わったらrebootしておいた方がいいかもしれない。（自分の環境だとrebootしないと実行に失敗した）


### ホストでやること

#### ドライバのコード取得

```shell
git clone https://github.com/Xilinx/dma_ip_drivers.git
chmod 777 -R dma_ip_driver/XDMA/linux-kernel/
```

#### ドライバのmake

```shell
cd dma_ip_driver/XDMA/linux-kernel/xdma
sudo make install
```

ここで

```shell
cp: cannot create regular file '/lib/modules/[linuxカーネルのバージョン的なの]/extra/xdma.ko': Permission denied
```

が出る場合は、あまり良くないが以下を実行。（rootでやっても自分の環境でもできなかった）

```shell
chmod 777 -R /lib 
```

#### toolのmake

```shell
cd ../tools
make
```

#### 実行

```shell
modprobe xdma
cd ../tests
sudo ./run_test.sh # sudoじゃないと動かなかった
```

#### 結果

```shell
Error at line 91, file reg_rw.c (22) [Invalid argument]                                                                                                       │
./run_test.sh: line 28: [: ==: unary operator expected                                                                                                        │
Error at line 91, file reg_rw.c (22) [Invalid argument]                                                                                                       │
./run_test.sh: line 28: [: ==: unary operator expected                                                                                                        │
Error at line 91, file reg_rw.c (22) [Invalid argument]                                                                                                       │
./run_test.sh: line 28: [: ==: unary operator expected                                                                                                        │
Info: Number of enabled h2c channels = 1                                                                                                                      │
./run_test.sh: line 44: [: ==: unary operator expected                                                                                                        │
Error at line 91, file reg_rw.c (22) [Invalid argument]                                                                                                       │
Error at line 91, file reg_rw.c (22) [Invalid argument]                                                                                                       │
Error at line 91, file reg_rw.c (22) [Invalid argument]                                                                                                       │
Info: Number of enabled c2h channels = 1                                                                                                                      │
Info: The PCIe DMA core is memory mapped.                                                                                                                     │
Info: Running PCIe DMA memory mapped write read test                                                                                                          │
      transfer size:  1024                                                                                                                                    │
      transfer count: 1                                                                                                                                       │
Info: Writing to h2c channel 0 at address offset 0.                                                                                                           │
Info: Wait for current transactions to complete.                                                                                                              │
/dev/xdma0_h2c_0 ** Average BW = 1024, 15.291114                                                                                                              │
Info: Writing to h2c channel 0 at address offset 1024.                                                                                                        │
Info: Wait for current transactions to complete.                                                                                                              │
/dev/xdma0_h2c_0 ** Average BW = 1024, 13.748103                                                                                                              │
Info: Writing to h2c channel 0 at address offset 2048.                                                                                                        │
Info: Wait for current transactions to complete.                                                                                                              │
/dev/xdma0_h2c_0 ** Average BW = 1024, 13.576580                                                                                                              │
Info: Writing to h2c channel 0 at address offset 3072.                                                                                                        │
Info: Wait for current transactions to complete.                                                                                                              │
/dev/xdma0_h2c_0 ** Average BW = 1024, 13.801841                                                                                                              │
Info: Reading from c2h channel 0 at address offset 0.                                                                                                         │
Info: Wait for the current transactions to complete.                                                                                                          │
/dev/xdma0_c2h_0 ** Average BW = 1024, 16.508408                                                                                                              │
Info: Reading from c2h channel 0 at address offset 1024.                                                                                                      │
Info: Wait for the current transactions to complete.                                                                                                          │
/dev/xdma0_c2h_0 ** Average BW = 1024, 16.165699                                                                                                              │
Info: Reading from c2h channel 0 at address offset 2048.                                                                                                      │
Info: Wait for the current transactions to complete.                                                                                                          │
/dev/xdma0_c2h_0 ** Average BW = 1024, 13.808727                                                                                                              │
Info: Reading from c2h channel 0 at address offset 3072.                                                                                                      │
Info: Wait for the current transactions to complete.                                                                                                          │
/dev/xdma0_c2h_0 ** Average BW = 1024, 13.420708                                                                                                              │
Info: Checking data integrity.                                                                                                                                │
Info: Data check passed for address range 0 - 1024.                                                                                                           │
Info: Data check passed for address range 1024 - 2048.                                                                                                        │
Info: Data check passed for address range 2048 - 3072.                                                                                                        │
Info: Data check passed for address range 3072 - 4096.                                                                                                        │
Info: All PCIe DMA memory mapped tests passed.                                                                                                                │
Info: All tests in run_tests.sh passed.
```

上の方にエラーが出て少しびっくりしてしまったが、
run_test.shの当該箇所はh2c(Host to Card)及びc2h(Card to Host)のチャンネル数を数えており、チャンネル数が4未満の場合はエラーが出るっぽい。

BRAMに転送、受診は出来ているっぽいので、ホストコードとipを少し弄り、DMAシステムへのipの接続を試していきたい。