はじめに
筆者は Ultra96/Ultra96-V2/KV260(ZynqMP) 向けに Debian GNU/Linux1 と Ubuntu20.042 を提供しています。また、XRT(Xilinx Runtime) はXilinx社が提供する開発環境(Vitis)で開発したプログラムをプラットフォームで動かすための環境です3。
本来なら MPSoC Edge Device 用の XRT は Xilinx が提供する Linux 環境(Petalinux) でしか動きませんが、XRT を Ultra96/Ultra96-V2/KV260 向け Debian GNU/Linux と Ubuntu20.04 で動かすための手順を幾つかのパートに分けて説明します。
- 概要編
- ビルド編
- XRT 2.11.0 ビルド編(この記事)
- XRT 2.8.1 ビルド編
- XRT 2.6.0 ビルド編
- インストール編
- 実践編
- Vitis編
この記事では XRT 2.11.0 を Ultra96/Ultra96-V2/KV260 向け Debian GNU/Linux および Ubuntu20.04用にビルドする手順について説明します。
注意
この記事で紹介している Debian Package は Xilinx 社の公式なものではありません。
XRT Debian Package の提供
XRT の Debian Package をビルドするためにはビルド環境を整えなければならず、とても面倒です。そこでビルド済みの Debian Package を用意しています。自分でビルドするのが面倒なかたはこちらをお使いください。
Debian 11 用
- リポジトリ: https://github.com/ikwzm/ZynqMP-FPGA-XRT
- ブランチ: 2021.1_EDGE_0_Debian_11
- パッケージファイル: xrt_202110.2.11.0_Edge_Debian_11-arm64.deb
fpga@debian-fpga:~/work$ git clone --depth 1 --branch 2021.1_EDGE_0_Debian_11 https://github.com/ikwzm/ZynqMP-FPGA-XRT.git
fpga@debian-fpga:~/work$ sudo apt install ./ZynqMP-FPGA-XRT/xrt_202110.2.11.0_Edge_Debian_11-arm64.deb
Ubuntu 20.04 用
- リポジトリ: https://github.com/ikwzm/ZynqMP-FPGA-XRT
- ブランチ: 2021.1_EDGE_0_Ubuntu_20.04
- パッケージファイル: xrt_202110.2.11.0_Edge_Ubuntu_20.04-arm64.deb
fpga@ubuntu-fpga:~/work$ git clone --depth 1 --branch 2021.1_EDGE_0_Ubuntu_20.04 https://github.com/ikwzm/ZynqMP-FPGA-XRT.git
fpga@ubuntu-fpga:~/work$ sudo apt install ./ZynqMP-FPGA-XRT/xrt_202110.2.11.0_Edge_Ubuntu_20.04-arm64.deb
XRT のビルド
ビルド環境
XRT を ZynqMP-FPGA-Linux 向けにビルドするのは少し面倒です。XRT のビルドには Ubuntu や CentOS などの Linux ディストリビューションが必要です。ビルドには色々な開発ツールがインストールされていなければなりません。さらに Debian Package を作るためか、PC をホストにして ARM64 用にクロスコンパイルするのがとても面倒です。
そこで、 Ultra96-V2 や KV260 に Debian または Ubuntu 20.04 を動かして、その上でセルフビルドします。Ultra96/Ultra96-V2/KV260 用の Debian 11 および Ubuntu 20.04 は以下の URL で公開しています。
XRT のダウンロード
以下の URL より XRT のソースコードをダウンロードします。ブランチは 2021.1_EDGE です。
- リポジトリ: https://github.com/Xilinx/XRT
- ブランチ: 2021.1_EDGE
このリポジトリは、 Xilinx 社が github に公開している https://github.com/Xilinx/XRT を fork して各種修正を加えたものです。修正内容は次章で説明します。
fpga@ubuntu-fpga:~$ cd work
fpga@ubuntu-fpga:~/work$ git clone --depth 1 --branch 2021.1https://github.com/Xilinx/XRT
Cloning into 'XRT'...
remote: Enumerating objects: 2370, done.
remote: Counting objects: 100% (2370/2370), done.
remote: Compressing objects: 100% (2001/2001), done.
remote: Total 2370 (delta 737), reused 807 (delta 325), pack-reused 0
Receiving objects: 100% (2370/2370), 24.12 MiB | 2.75 MiB/s, done.
Resolving deltas: 100% (737/737), done.
Updating files: 100% (2161/2161), done.
ビルドに必要な Debian Package をインストール
ビルドに必要なパッケージをインストールします。幸い XRT には、ビルドに必要なパッケージをインストールするスクリプト ./src/runtime_src/tools/scripts/xrtdeps.sh が用意されています。
./src/runtime_src/tools/scripts/xrtdeps.sh を super user 権限で実行すると、apt プログラムによって足りない Debian Package がインストールされます。
fpga@ubuntu-fpga:~/work/XRT$ sudo ./src/runtime_src/tools/scripts/xrtdeps.sh
Preparing ubuntu ...
Installing packages...
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
:
(後略)
:
ビルド
build ディレクトリに移動して、そこにある build.sh に "-edge" オプションをつけて実行することで、ビルドが開始されます。私のUltra96/Ultra96-V2/KV260 の環境だと、並列処理するコア数がデフォルトの4のままだと、途中で make コマンドがエラー終了しました。そこでコア数を1にするために "-j 1" オプションをつけています。Ultra96/Ultra96-V2 だとけっこう時間がかかります。私の環境では1時間20分ほどかかりました。
fpga@debian-fpga:~/work/XRT$ cd build/
fpga@ubuntu-fpga:~/work/XRT/build$ ./build.sh -edge -j 1
XRT_EDGE_BUILD=yes cmake -DRDI_CCACHE=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../src
-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found UnixCommands: /bin/bash
-- Host system processor is aarch64
-- Target system processor is aarch64
-- Checking for module 'libdrm'
-- Found libdrm, version 2.4.104
-- Looking for DRM - found at /usr 2.4.104
-- Checking for module 'OpenCL'
-- Found OpenCL, version 3.0
-- Looking for OPENCL - found at /usr 3.0 /usr/include
-- Found Git: /usr/bin/git (found version "2.30.2")
-- Looking for GIT - found at /usr/bin/git
-- Found Boost: /usr/lib/aarch64-linux-gnu/cmake/Boost-1.74.0/BoostConfig.cmake\ (found version "1.74.0") found components: system filesystem program_options
-- Found Curses: /usr/lib/aarch64-linux-gnu/libcurses.so
-- XRT EA eula files /home/fpga/work/tmp/XRT/src/../LICENSE
-- Platform/Linux (Debian) (Kernel 5.10.0-xlnx-v2021.1-zynqmp-fpga)
-- Compiler: /usr/bin/c++ /usr/bin/cc
-- kernel-doc downloading
-- Found OpenSSL: /usr/lib/aarch64-linux-gnu/libcrypto.so (found version "1.1.1k")
-- RapidJSON found. Headers: /usr/include :
-- Found GTest: /usr/lib/aarch64-linux-gnu/libgtest.a
-- XRT xrt++ header files
-- xrt++.hpp
-- xrtexec.hpp
CMake Warning at runtime_src/ert/CMakeLists.txt:52 (message):
****************************************************************
No firmware files built or copied, resulting XRT package will be missing
ERT scheduler firmware. Use build.sh -ertfw <dir> to specify path to a
directory with firmware to copy during XRT build.
****************************************************************
-- XRT deprecated header files
-- xrt.h
-- XRT header files for MPSoC only
-- xclhal2_mpsoc.h
-- sk_types.h
-- Found Protobuf: /usr/lib/aarch64-linux-gnu/libprotobuf.so;-lpthread (found version "3.12.4")
-- Found PythonLibs: /usr/lib/aarch64-linux-gnu/libpython3.9.so (found suitable version "3.9.2", minimum required is "3.4.0")
-- Python libs version: 3.9.2
-- PYTHON_INCLUDE_PATH /usr/include/python3.9
-- Found PythonInterp: /usr/bin/python3 (found version "3.9.2")
-- Found PythonLibs: /usr/lib/aarch64-linux-gnu/libpython3.9.so
-- Performing Test HAS_FLTO
-- Performing Test HAS_FLTO - Success
-- Found pybind11: /usr/local/lib/python3.9/dist-packages/pybind11/include (found version "2.9.1")
-- Looking for CL_VERSION_2_2
-- Looking for CL_VERSION_2_2 - found
-- Found OpenCL: /usr/lib/aarch64-linux-gnu/libOpenCL.so (found version "2.2")
-- XRT version: 2.11.0
-- Release DEB package
-- XRT DRIVER SRC BASE DIR /home/fpga/work/tmp/XRT/src/runtime_src/core
-- Preparing OpenCL ICD xilinx.icd
-- Preparing XRT pkg-config
-- Coverity tool not found and will be skipped
-- Preparing XRT find_package
-- Configuring done
-- Generating done
-- Build files have been written to: /home/fpga/work/tmp/XRT/build/Edge
real 0m13.350s
user 0m7.333s
sys 0m2.241s
make -j 1 DESTDIR=/home/fpga/work/tmp/XRT/build/Edge install
:
(中略)
:
real 1m19.102s
user 1m4.807s
sys 0m14.210s
ビルドが終了すると、build/Edge ディレクトリの下に Debian Package が出来ています。
fpga@debian-fpga:~/work/XRT/build$ ls -1 Edge/xrt_*
Edge/xrt_202110.2.11.0_Edge_Debian_11-arm64.deb
Edge/xrt_202110.2.11.0_Edge_Debian_11-arm64.tar.gz
このうち Ultra96/Ultra96-V2 に必要な Debian Package は、Edge/xrt_202110.2.11.0_Edge_Debian_11-arm64.deb です。
XRT の変更内容
この章では、オリジナルの XRT(https://github.com/Xilinx/XRT ブランチ2021.1) に対して、私が独自に変更した点について説明します。
Debian 11 に対応
Debian 11 の gcc および g++ のバージョンは10です。しかし、ビルドに必要な Debian Package をインストールするスクリプト ./src/runtime_src/tools/scripts/xrtdeps.sh はバージョン8を想定しています。そこでこのスクリプトを次のように修正します。
diff --git a/src/runtime_src/tools/scripts/xrtdeps.sh b/src/runtime_src/tools/scripts/xrtdeps.sh
index 60f2976d0..a8f2577a6 100755
--- a/src/runtime_src/tools/scripts/xrtdeps.sh
+++ b/src/runtime_src/tools/scripts/xrtdeps.sh
@@ -219,8 +219,13 @@ ub_package_list()
# Use GCC8 on ARM64 Ubuntu as GCC7 randomly crashes with Internal Compiler Error on
# Travis CI ARM64 platform
if [ $ARCH == "aarch64" ]; then
- UB_LIST+=( gcc-8 )
- UB_LIST+=( g++-8 )
+ if [ $FLAVOR == "debian" ] && [ $MAJOR == 11 ]; then
+ UB_LIST+=( gcc-10 )
+ UB_LIST+=( g++-10 )
+ else
+ UB_LIST+=( gcc-8 )
+ UB_LIST+=( g++-8 )
+ fi
fi
}
XRT_EDGE_BUILD を追加
オリジナルではホストプロセッサとターゲットプロセッサが同じ場合に XRT_NATIVE_BUILD という変数が "yes" にセットされます。 そして、XRT_NATIVE_BUILD が "yes" の時(ホストプロセッサとターゲットプロセッサが同じ時)に src/runtime_src/core/pcie が、"no" の時(ホストプロセッサとターゲットプロセッサが異なる時)に src/runtime_src/core/edge がビルドされるように src/runtime_src/core/CMakeLists.txt が定義されています。
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
add_subdirectory(include)
if (${XRT_NATIVE_BUILD} STREQUAL "yes")
add_subdirectory(common)
add_subdirectory(pcie)
add_subdirectory(tools)
else()
add_subdirectory(common)
add_subdirectory(edge)
add_subdirectory(tools)
endif()
また、XRT_NATIVE_BUILD が "yes" の時(ホストプロセッサとターゲットプロセッサが同じ時)にインクルードされる src/CMake/nativeLnx.cmake には、次のようにホスト用のドライバをビルド&インストールするようになっています。
:
(前略)
:
include (CMake/dkms.cmake)
include (CMake/dkms-aws.cmake)
include (CMake/dkms-azure.cmake)
include (CMake/dkms-container.cmake)
:
(後略)
Ultra96-V2 や KV260 に Debian 11 および Ubuntu 20.04 を動かしてその上でセルフビルドする場合は、ホストプロセッサとターゲットプロセッサが同じ arm64 になります。このままだと、edge 用のではなく pcie 用にビルドされてしまいます。
そこで、次のように src/CMakfile.txt に XRT_EDGE_BUILD 変数を追加します。
:
(前略)
:
set(XRT_EDGE_BUILD "no")
if (XRT_NATIVE_BUILD STREQUAL "no")
set(XRT_EDGE_BUILD "no")
endif()
if (DEFINED ENV{XRT_EDGE_BUILD})
set(XRT_EDGE_BUILD $ENV{XRT_EDGE_BUILD})
endif()
:
(後略)
そして XRT_EDGE_BUILD が "yes" の場合は edge 用のビルドを行うように、それぞれのファイルを変更します。
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
add_subdirectory(include)
if (${XRT_EDGE_BUILD} STREQUAL "yes")
add_subdirectory(common)
add_subdirectory(edge)
add_subdirectory(tools)
else()
add_subdirectory(common)
add_subdirectory(pcie)
add_subdirectory(tools)
endif()
:
(前略)
:
if (${XRT_EDGE_BUILD} STREQUAL "yes")
include (CMake/dkms-edge.cmake)
else()
include (CMake/dkms.cmake)
include (CMake/dkms-aws.cmake)
include (CMake/dkms-azure.cmake)
include (CMake/dkms-container.cmake)
endif()
:
(後略)
また、XRT_NATIVE_BUILD が "yes" の時(ホストプロセッサとターゲットプロセッサが同じ時)、コンパイルのオプションに "-Wall" と -"Werror" が追加されるような設定が src/runtime_src/CMakeLists.txt にあります。
:
(前略)
:
# TODO CL_TARGET_OPENCL_VERSION is not defined..
if (${XRT_NATIVE_BUILD} STREQUAL "yes")
add_compile_options("-Wall" "-Werror")
endif()
:
(後略)
"-Werror" オプションがあると src/runtime_src/core/edge 以下のビルド時にエラーが出てコンパイルに失敗します。そこで XRT_EDGE_BUILD が "yes" の時はコンパイルオプションに "-Wall" と "-Werror" が追加されないように src/runtime_src/CMakeLists.txt を修正します。
:
(前略)
:
# TODO CL_TARGET_OPENCL_VERSION is not defined..
if (${XRT_EDGE_BUILD} STREQUAL "no")
add_compile_options("-Wall" "-Werror")
endif() :
(後略)
最後に build/build.sh を修正して、ホストプロセッサが arm64 かつ "-edge" オプションが追加された場合は XRT_EDGE_BUILD が "yes" になるように修正します。
:
(前略)
:
if [[ $CPU == "aarch64" ]] && [[ $edge == 1 ]]; then
mkdir -p $edge_dir
cd $edge_dir
if [[ $nocmake == 0 ]]; then
echo "XRT_EDGE_BUILD=yes $CMAKE -DRDI_CCACHE=$ccache -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../src"
time env XRT_EDGE_BUILD=yes $CMAKE -DRDI_CCACHE=$ccache -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ../../src
fi
if [[ $nobuild == 0 ]]; then
echo "make -j $jcore $verbose DESTDIR=$PWD install"
time make -j $jcore $verbose DESTDIR=$PWD install
if [[ $noctest == 0 ]]; then
time ctest --output-on-failure
fi
time make package
fi
if [[ $docs == 1 ]]; then
echo "make xrt_docs"
make xrt_docs
fi
fi
:
(後略)
パッケージファイル名を変更
オリジナルの XRT では、ビルドした Debian Package の名前は xrt_202010.2.8.0_18.04-arm64-xrt.deb になりますが、Debian 11 用またはUbuntu 用のパッケージであることを明示するために、次のようにEdge というキーワードとともに Linux のフレーバー名を追加しておきます。
diff --git a/src/CMake/cpackLin.cmake b/src/CMake/cpackLin.cmake
index 2cc895182..cb59a320a 100644
--- a/src/CMake/cpackLin.cmake
+++ b/src/CMake/cpackLin.cmake
@@ -80,9 +80,9 @@ if (${LINUX_FLAVOR} MATCHES "^(Ubuntu|Debian)")
SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "armhf")
SET(CPACK_ARCH "aarch32")
endif()
- SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/prerm")
- SET(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_XRT_PACKAGE_DEPENDS})
endif()
+ SET(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_BINARY_DIR}/postinst;${CMAKE_CURRENT_BINARY_DIR}/prerm")
+ SET(CPACK_DEBIAN_PACKAGE_DEPENDS ${CPACK_DEBIAN_XRT_PACKAGE_DEPENDS})
elseif (${LINUX_FLAVOR} MATCHES "^(RedHat|CentOS|Amazon|Fedora|SUSE)")
execute_process(
@@ -144,7 +144,11 @@ else ()
SET (CPACK_GENERATOR "TGZ")
endif()
-SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${XRT_VERSION_RELEASE}.${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CPACK_REL_VER}-${CPACK_ARCH}")
+if (${XRT_EDGE_BUILD} STREQUAL "yes")
+ SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${XRT_VERSION_RELEASE}.${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_Edge_${LINUX_FLAVOR}_${CPACK_REL_VER}-${CPACK_ARCH}")
+else()
+ SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${XRT_VERSION_RELEASE}.${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CPACK_REL_VER}-${CPACK_ARCH}")
+endif()
message("-- ${CMAKE_BUILD_TYPE} ${PACKAGE_KIND} package")
不要なテストの削除
Debian Package のビルド時に、ビルドしたツールが正常に動作するかテストが行われます。しかし、Xilinx オリジナルのままでは、Edge 用の Debian Package にもかかわらず、PCI-Express 用のツールである xbmgmt と xbutil のテストを試みようとして失敗します。どこで、src/CMake/NativeTests.cmake を次のように修正して不要なテストを行わないようにします。
diff --git a/src/CMake/nativeTests.cmake b/src/CMake/nativeTests.cmake
index 591797e5c..c05af8041 100644
--- a/src/CMake/nativeTests.cmake
+++ b/src/CMake/nativeTests.cmake
@@ -3,13 +3,17 @@
# XRT_INSTALL_BIN_DIR
enable_testing()
+if (${XRT_EDGE_BUILD} STREQUAL "no")
add_test(NAME xbmgmt
COMMAND ${CMAKE_BINARY_DIR}/runtime_src/core/pcie/tools/xbmgmt/xbmgmt scan
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+endif()
+if (${XRT_EDGE_BUILD} STREQUAL "no")
add_test(NAME xbutil
COMMAND ${CMAKE_BINARY_DIR}/runtime_src/core/pcie/tools/xbutil/xbutil scan
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+endif()
add_test(NAME xbutil2
COMMAND ${CMAKE_BINARY_DIR}/runtime_src/core/tools/xbutil2/xbutil2 examine
@@ -26,4 +30,6 @@ add_test(NAME python_binding
set_tests_properties(python_binding PROPERTIES ENVIRONMENT
"PYTHONPATH=.${CMAKE_INSTALL_PREFIX}/${XRT_INSTALL_DIR}/python;XILINX_XRT=.${CMAKE_INSTALL_PREFIX}/${XRT_INSTALL_DIR}")
-set_tests_properties(xbutil xbmgmt PROPERTIES ENVIRONMENT INTERNAL_BUILD=1)
+if (${XRT_EDGE_BUILD} STREQUAL "no")
+ set_tests_properties(xbutil xbmgmt PROPERTIES ENVIRONMENT INTERNAL_BUILD=1)
+endif()
zocl ドライバオープン時の修正
Xilinx オリジナルでは、XRT が zocl(XRT Edge 用の Linux Kernel Module) をオープンする際に指定するファイル名を "/dev/dri/renderD128" に固定しています。このままでは、例えば[『Ultra96/Ultra96-V2 向け Debian GNU/Linux で Lima Driverを動かす』]で紹介したように、他の DRM ドライバと共存するのが難しくなります。そこで、zocl をオープンする際、/dev/dri をサーチして "zocl" を探すようにします。
具体的には、src/runtime_src/core/edge/user/zynq_dev.h と src/runtime_src/core/edge/zynq_dev.c を次のように修正して、/dev/dri から zocl を検索するようにします。
diff --git a/src/runtime_src/core/edge/user/zynq_dev.h b/src/runtime_src/core/edge/user/zynq_dev.h
index 76ce580de..8d1e92b0c 100644
--- a/src/runtime_src/core/edge/user/zynq_dev.h
+++ b/src/runtime_src/core/edge/user/zynq_dev.h
@@ -49,15 +49,26 @@ public:
const std::vector<char>& buf);
std::string get_sysfs_path(const std::string& entry);
- static zynq_device *get_dev();
-private:
+ static zynq_device *get_dev(unsigned index = 0);
+
std::fstream sysfs_open(const std::string& entry, std::string& err,
bool write = false, bool binary = false);
+ static zynq_device dummy_device;
+ static std::string dri_root;
+ static std::string drm_name;
+ static std::string render_prefix;
+
+ int index;
+ std::string render_name;
+ std::string device_path;
std::string sysfs_root;
- zynq_device(const std::string& sysfs_base);
- zynq_device(const zynq_device& s) = delete;
- zynq_device& operator=(const zynq_device& s) = delete;
+
+ bool available(void)
+ {
+ return (index >= 0);
+ }
+ zynq_device(const std::string& render_name, int index);
};
#endif
diff --git a/src/runtime_src/core/edge/user/zynq_dev.cpp b/src/runtime_src/core/edge/user/zynq_dev.cpp
index b8fb89dee..8a554813b 100644
--- a/src/runtime_src/core/edge/user/zynq_dev.cpp
+++ b/src/runtime_src/core/edge/user/zynq_dev.cpp
@@ -20,6 +20,96 @@
#include <cstring>
#include "zynq_dev.h"
+#include <memory>
+#include <mutex>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <libdrm/drm.h>
+#include <libdrm/drm_mode.h>
+
+class zynq_device_scanner {
+ private:
+ std::mutex lock;
+ std::vector<zynq_device> device_list;
+
+ int strncmp(const char* s1, const std::string& s2)
+ {
+ return std::strncmp(s1, s2.c_str(), s2.length());
+ }
+ void rescan_nolock(void)
+ {
+ DIR* dp = opendir(zynq_device::dri_root.c_str());
+ if (dp) {
+ int index = 0;
+ struct dirent* entry;
+ drm_version version;
+ const std::unique_ptr<char[]> name(new char[128]);
+ const std::unique_ptr<char[]> desc(new char[512]);
+ const std::unique_ptr<char[]> date(new char[128]);
+ std::memset(&version, 0, sizeof(version));
+ version.name = name.get();
+ version.name_len = 128;
+ version.desc = desc.get();
+ version.desc_len = 512;
+ version.date = date.get();
+ version.date_len = 128;
+
+ while ((entry = readdir(dp))) {
+ int fd;
+ std::string render_name(entry->d_name);
+ if (strncmp(entry->d_name, zynq_device::render_prefix) != 0)
+ continue;
+ std::string dev_path = zynq_device::dri_root + "/" + render_name;
+ if ((fd = open(dev_path.c_str(), O_RDWR, 0)) < 0)
+ continue;
+ if (ioctl(fd, DRM_IOCTL_VERSION, &version) == 0) {
+ if (strncmp(version.name, zynq_device::drm_name) == 0) {
+ device_list.insert(device_list.end(), zynq_device(render_name, index));
+ index++;
+ }
+ }
+ close(fd);
+ }
+ closedir(dp);
+ }
+ }
+
+ public:
+ static zynq_device_scanner *get()
+ {
+ static zynq_device_scanner scanner;
+ return &scanner;
+ }
+
+ zynq_device* get_dev(unsigned index)
+ {
+ std::lock_guard<std::mutex> l(lock);
+ if (index < device_list.size())
+ return &device_list[index];
+ else
+ return &zynq_device::dummy_device;
+ }
+
+ void rescan(void)
+ {
+ std::lock_guard<std::mutex> l(lock);
+ rescan_nolock();
+ }
+
+ size_t device_num_total(void)
+ {
+ std::lock_guard<std::mutex> l(lock);
+ return device_list.size();
+ }
+
+ private:
+ zynq_device_scanner(void) { rescan_nolock();}
+ zynq_device_scanner(const zynq_device_scanner& s) = delete;
+ zynq_device_scanner& operator=(const zynq_device_scanner& s) = delete;
+};
+
static std::fstream sysfs_open_path(const std::string& path, std::string& err,
bool write, bool binary)
{
@@ -139,15 +229,20 @@ void zynq_device::sysfs_get(const std::string& entry, std::string& err_msg,
s = ""; // default value
}
-zynq_device *zynq_device::get_dev()
+zynq_device *zynq_device::get_dev(unsigned index)
{
- // This is based on the fact that on edge devices, we only have one DRM
- // device, which is named renderD128.
- // This path is reliable. It is the same for ARM32 and ARM64.
- static zynq_device dev("/sys/class/drm/renderD128/device/");
- return &dev;
+ return zynq_device_scanner::get()->get_dev(index);
}
-zynq_device::zynq_device(const std::string& root) : sysfs_root(root)
+zynq_device::zynq_device(const std::string& render_name, int index)
+ : index(index)
+ , render_name(render_name)
+ , device_path(dri_root + "/" + render_name)
+ , sysfs_root("/sys/class/drm/" + render_name + "/device/")
{
}
+
+zynq_device zynq_device::dummy_device ("renderD128", -1);
+std::string zynq_device::dri_root ("/dev/dri");
+std::string zynq_device::drm_name ("zocl" );
+std::string zynq_device::render_prefix("renderD" );
src/runtime_src/core/edge/user/device_linux.c を 次のように修正します。
diff --git a/src/runtime_src/core/edge/user/device_linux.cpp b/src/runtime_src/core/edge/user/device_linux.cpp
index 00e20a250..5fdd7c7d3 100644
--- a/src/runtime_src/core/edge/user/device_linux.cpp
+++ b/src/runtime_src/core/edge/user/device_linux.cpp
@@ -330,7 +330,6 @@ struct aie_reg_read
#ifdef XRT_ENABLE_AIE
#ifndef __AIESIM__
const static std::string AIE_TAG = "aie_metadata";
- const static std::string ZOCL_DEVICE = "/dev/dri/renderD128";
const uint32_t major = 1;
const uint32_t minor = 0;
const uint32_t patch = 0;
@@ -355,9 +354,9 @@ struct aie_reg_read
% pt.get<uint32_t>("schema_version.minor")
% pt.get<uint32_t>("schema_version.patch")));
- int mKernelFD = open(ZOCL_DEVICE.c_str(), O_RDWR);
+ int mKernelFD = open(dev->device_path.c_str(), O_RDWR);
if (!mKernelFD)
- throw xrt_core::error(-EINVAL, boost::str(boost::format("Cannot open %s") % ZOCL_DEVICE));
+ throw xrt_core::error(-EINVAL, boost::str(boost::format("Cannot open %s") % dev->device_path));
XAie_DevInst* devInst; // AIE Device Instance
src/runtime_src_core/edge/user/shim.cpp にあるクラス shim のコンストラクタを次のように修正して mDev インスタンス変数に zynq_device.get_dev() で得たデバイス情報をセットします。
diff --git a/src/runtime_src/core/edge/user/shim.cpp b/src/runtime_src/core/edge/user/shim.cpp
index 89c720795..aaa2c8214 100644
--- a/src/runtime_src/core/edge/user/shim.cpp
+++ b/src/runtime_src/core/edge/user/shim.cpp
@@ -28,6 +28,7 @@
#include "core/common/config_reader.h"
#include "core/common/query_requests.h"
#include "core/common/error.h"
+#include "shim_int.h"
#include <cerrno>
#include <iostream>
@@ -40,6 +41,7 @@
#include <cstdarg>
#include <fcntl.h>
+#include <dirent.h>
#include <poll.h>
#include <unistd.h>
#include <sys/ioctl.h>
@@ -108,12 +110,17 @@ shim(unsigned index)
{
xclLog(XRT_INFO, "%s", __func__);
- mKernelFD = open("/dev/dri/renderD128", O_RDWR);
- if (mKernelFD < 0) {
- xclLog(XRT_ERROR, "%s: Cannot open /dev/dri/renderD128", __func__);
+ mDev = zynq_device::get_dev(index);
+ if (mDev->available()) {
+ mKernelFD = open(mDev->device_path.c_str(), O_RDWR, 0);
+ if (mKernelFD < 0) {
+ xclLog(XRT_ERROR, "%s: Cannot open device %s", __func__, mDev->device_path.c_str());
+ }
+ } else {
+ mKernelFD = -1;
+ xclLog(XRT_ERROR, "%s: Card [%d] not found", __func__, index);
}
mCmdBOCache = std::make_unique<xrt_core::bo_cache>(this, xrt_core::config::get_cmdbo_cache());
- mDev = zynq_device::get_dev();
}
src/runtime_src_core/edge/user/shim.cpp にあるxclGetSysfsPath() と getIPCountAddNames() を次のように mDev インスタンス変数のデバイスクラスの get_sysfs_path() を呼び出すように変更します。
#ifndef __HWEM__
@@ -688,7 +695,7 @@ std::string
shim::
xclGetSysfsPath(const std::string& entry)
{
- return zynq_device::get_dev()->get_sysfs_path(entry);
+ return mDev->get_sysfs_path(entry);
}
int
@@ -1349,9 +1356,8 @@ getIPCountAddrNames(int type,
size_t size)
{
debug_ip_layout *map;
- auto dev = zynq_device::get_dev() ;
std::string entry_str = "debug_ip_layout";
- std::string path = dev->get_sysfs_path(entry_str);
+ std::string path = mDev->get_sysfs_path(entry_str);
std::ifstream ifs(path.c_str(), std::ifstream::binary);
uint32_t count = 0;
char buffer[65536];
src/runtime_src_core/edge/user/shim.cpp にある xclProbe() と xclOpen() を次のように修正します。
@@ -1590,32 +1596,7 @@ unsigned
xclProbe()
{
PROBE_CB;
-
- int fd = open("/dev/dri/renderD128", O_RDWR);
- if (fd < 0) {
- return 0;
- }
- std::vector<char> name(128,0);
- std::vector<char> desc(512,0);
- std::vector<char> date(128,0);
- drm_version version;
- std::memset(&version, 0, sizeof(version));
- version.name = name.data();
- version.name_len = 128;
- version.desc = desc.data();
- version.desc_len = 512;
- version.date = date.data();
- version.date_len = 128;
-
- int result = ioctl(fd, DRM_IOCTL_VERSION, &version);
- if (result) {
- close(fd);
- return 0;
- }
-
- result = std::strncmp(version.name, "zocl", 4);
- close(fd);
- return (result == 0) ? 1 : 0;
+ return (zynq_device::get_dev()->available());
}
#endif
@@ -1624,7 +1605,7 @@ xclOpen(unsigned deviceIndex, const char*, xclVerbosityLevel)
{
try {
//std::cout << "xclOpen called" << std::endl;
- if (deviceIndex >= xclProbe()) {
+ if (zynq_device::get_dev(deviceIndex)->available() == false) {
xrt_core::message::send(xrt_core::message::severity_level::info, "XRT",
std::string("Cannot find index " + std::to_string(deviceIndex) + " \n"));
return nullptr;
@@ -1652,6 +1633,22 @@ xclOpen(unsigned deviceIndex, const char*, xclVerbosityLevel)
}
Ubuntu 20.04 の static link 時の修正
Ubuntu 20.04 用にビルドする際は src/CMake/nativeLnx.cmake で次のように XRT_STATIC_BUILD が "on" に設定されます。
# Static linking creates and installs static tools and libraries. The
# static libraries have system boost dependencies which must be
# resolved in final target. The tools (currently xbutil2 and xbmgmt2)
# will be statically linked. Enabled only for ubuntu.
option(XRT_STATIC_BUILD "Enable static building of XRT" OFF)
if ( (${CMAKE_VERSION} VERSION_GREATER "3.16.0")
AND (${XRT_NATIVE_BUILD} STREQUAL "yes")
AND (${LINUX_FLAVOR} MATCHES "^(Ubuntu)")
)
message("-- Enabling static artifacts of XRT")
set(XRT_STATIC_BUILD ON)
endif()
XRT_STATIC_BUILD が "on" の場合、xbmgmt2 と xbutil2 の static link バージョンも同時にビルドしますが、その際、リンク時にシンボルが見つからないというエラーが発生します。これは src/runtime_src/core/edge/user/shim.c の関数定義が間違っているためです。そこで次のように src/runtime_src/core/edge/user/shim.c を修正します。
+xclDeviceHandle
+xclOpenByBDF(const char *bdf)
+{
+ try {
+ return xclOpen(0, nullptr, XCL_QUIET);
+ }
+ catch (const xrt_core::error& ex) {
+ xrt_core::send_exception_message(ex.what());
+ }
+ catch (const std::exception& ex) {
+ xrt_core::send_exception_message(ex.what());
+ }
+
+ return nullptr;
+}
+
void
xclClose(xclDeviceHandle handle)
{
@@ -2269,49 +2266,82 @@ xclRegisterInterruptNotify(xclDeviceHandle handle, unsigned int userInterrupt, i
}
int
-xclCreateWriteQueue(xclDeviceHandle handle, xclQueueContext *q_ctx, void **q_hdl)
+xclCreateWriteQueue(xclDeviceHandle handle, xclQueueContext *q_ctx, uint64_t *q_hdl)
{
return -ENOSYS;
}
int
-xclCreateReadQueue(xclDeviceHandle handle, xclQueueContext *q_ctx, void **q_hdl)
+xclCreateReadQueue(xclDeviceHandle handle, xclQueueContext *q_ctx, uint64_t *q_hdl)
{
return -ENOSYS;
}
int
-xclDestroyQueue(xclDeviceHandle handle, void *q_hdl)
+xclDestroyQueue(xclDeviceHandle handle, uint64_t q_hdl)
{
return -ENOSYS;
}
int
-xclModifyQueue(xclDeviceHandle handle, void *q_hdl)
+xclModifyQueue(xclDeviceHandle handle, uint64_t q_hdl)
{
return -ENOSYS;
}
int
-xclStartQueue(xclDeviceHandle handle, void *q_hdl)
+xclStartQueue(xclDeviceHandle handle, uint64_t q_hdl)
{
return -ENOSYS;
}
int
-xclStopQueue(xclDeviceHandle handle, void *q_hdl)
+xclStopQueue(xclDeviceHandle handle, uint64_t q_hdl)
{
return -ENOSYS;
}
ssize_t
-xclWriteQueue(xclDeviceHandle handle, void *q_hdl, xclQueueRequest *wr_req)
+xclWriteQueue(xclDeviceHandle handle, uint64_t q_hdl, struct xclQueueRequest *wr_req)
{
return -ENOSYS;
}
ssize_t
-xclReadQueue(xclDeviceHandle handle, void *q_hdl, xclQueueRequest *wr_req)
+xclReadQueue(xclDeviceHandle handle, uint64_t q_hdl, struct xclQueueRequest *rd_req)
+{
+ return -ENOSYS;
+}
+
+int
+xclPollQueue(xclDeviceHandle handle, uint64_t q_hdl, int min_compl,
+ int max_compl, struct xclReqCompletion *comps,
+ int* actual_compl, int timeout)
+{
+ return -ENOSYS;
+}
+
+int
+xclSetQueueOpt(xclDeviceHandle handle, uint64_t q_hdl, int type, uint32_t val)
+{
+ return -ENOSYS;
+}
+
+int
+xclPollCompletion(xclDeviceHandle handle, int min_compl, int max_compl,
+ struct xclReqCompletion *comps, int* actual_compl, int timeout)
+{
+ return -ENOSYS;
+}
+
+void*
+xclAllocQDMABuf(xclDeviceHandle handle, size_t size, uint64_t *buf_hdl)
+{
+ return NULL;
+}
+
+int
+xclFreeQDMABuf(xclDeviceHandle handle, uint64_t buf_hdl)
{
return -ENOSYS;
}
参考
- https://github.com/Xilinx/XRT
- https://github.com/ikwzm/ZynqMP-FPGA-XRT
- https://github.com/ikwzm/ZynqMP-FPGA-Linux
- https://github.com/ikwzm/ZynqMP-FPGA-Ubuntu20.04
- 『UltraZed/Ultra96/Ultra96-V2/KV260 向け Debian GNU/Linux (v2021.1版) ブートイメージの提供』@Qiita
- 『Ultra96/Ultra96-V2 向け Debian GNU/Linux で Lima Driverを動かす』@Qiita