核 Compute Accelerators 子系統(tǒng):DRM_ACCEL 框架的設(shè)計、配置與驅(qū)動接入)
Linux 內(nèi)核 Compute Accelerators 子系統(tǒng)DRM_ACCEL 框架的設(shè)計、配置與驅(qū)動接入【免費下載鏈接】linuxLinux kernel source tree項目地址: https://gitcode.com/GitHub_Trending/li/linux本文基于內(nèi)核倉庫中的 Compute Accelerators 子系統(tǒng)介紹文檔系統(tǒng)講解 Linux 計算加速器Compute Accelerators子系統(tǒng)的定位、設(shè)備分類、與 DRM 子系統(tǒng)的復(fù)用關(guān)系以及驅(qū)動開發(fā)者接入該框架的完整步驟從CONFIG_DRM_ACCEL配置到DRIVER_COMPUTE_ACCEL特性標志、accel_open()與DEFINE_DRM_ACCEL_FOPS宏的使用再到 major 號 261、/dev/accel/*設(shè)備節(jié)點等用戶空間暴露約定的源碼級實現(xiàn)。讀完后你將能夠判斷一款加速卡是否適合接入該框架并知道在驅(qū)動中做哪兩處改動即可把設(shè)備暴露為標準 accel 設(shè)備。1. 子系統(tǒng)定位以統(tǒng)一方式向用戶空間暴露計算加速器Linux 計算加速器子系統(tǒng)compute accelerators subsystem的設(shè)計目標是以統(tǒng)一的方式向用戶空間暴露計算加速器并提供一組通用的基礎(chǔ)功能引自 introduction.rst。覆蓋的設(shè)備形態(tài)包括兩類獨立的 ASIC 芯片stand-alone ASICs集成在 SoC 或 GPU 內(nèi)部的 IP 塊。這些設(shè)備通常被設(shè)計用來加速機器學(xué)習(xí)ML和深度學(xué)習(xí)DL計算但accel 層并不局限于這一類加速器——它是一個更通用的“計算加速設(shè)備”框架。1.1 文檔給出的三類典型設(shè)備原文檔將計算加速器歸納為三類接入驅(qū)動設(shè)計時可直接作為硬件能力評估的參照類別部署形態(tài)關(guān)鍵硬件特征Edge AI邊緣 AI邊緣設(shè)備上的推理如嵌入式 ASIC/FPGA或 SoC 內(nèi)部 IP例如筆記本攝像頭通常通過寄存器配置可帶 DMA 也可不帶 DMAInference>if DRM menuconfig DRM_ACCEL bool Compute Acceleration Framework help Framework for device drivers of compute acceleration devices, such as, but not limited to, Machine-Learning and Deep-Learning acceleration devices. ... This framework is integrated with the DRM subsystem as compute accelerators and GPUs share a lot in common and can use almost the same infrastructure code. Having said that, acceleration devices will have a different major number than GPUs, and will be exposed to user-space using different device files, called accel/accel* (in /dev, sysfs and debugfs). source drivers/accel/amdxdna/Kconfig source drivers/accel/ethosu/Kconfig source drivers/accel/habanalabs/Kconfig source drivers/accel/ivpu/Kconfig source drivers/accel/qaic/Kconfig source drivers/accel/rocket/Kconfig endif要點該選項是框架級開關(guān)menuconfig DRM_ACCEL只有CONFIG_DRM開啟時才可見幫助文本明確說明加速器與 GPU “共用大量公共部分幾乎可以復(fù)用同一套基礎(chǔ)設(shè)施代碼”但會采用不同的 major 號并以accel/accel*的命名在/dev、sysfs 和 debugfs 中暴露框架之下當前掛接的具體設(shè)備驅(qū)動 Kconfig 有amdxdna、ethosu、habanalabs、ivpu、qaic、rocket與 drivers/accel/Makefile 所組織的子目錄一一對應(yīng)目錄結(jié)構(gòu)即為drivers/accel/{amdxdna,ethosu,habanalabs,ivpu,qaic,rocket}加框架核心drm_accel.c。因此開發(fā)者接入的第一步就是確認內(nèi)核已配置CONFIG_DRM_ACCEL文檔“Getting Started”一節(jié)的要求。3. 與 GPU 的區(qū)分獨立 major 號與設(shè)備命名約定為了防止龐大的用戶空間圖形軟件棧Mesa 等把加速器誤當作 GPU 來使用原文檔“Differentiation from GPUs”一節(jié)規(guī)定了兩條隔離手段使用全新的 major 號 新的設(shè)備字符文件把加速器與 GPU 在用戶空間層面區(qū)隔開驅(qū)動源碼單獨放在內(nèi)核樹的drivers/accel/目錄而不是drivers/gpu/drm/之下。加速器設(shè)備以專用 major 號 261暴露給用戶空間并遵循如下命名約定暴露位置約定設(shè)備字符文件/dev/accel/accel*sysfs/sys/class/accel/accel*/debugfs/sys/kernel/debug/accel/*/3.1 major 號 261 的定義ACCEL_MAJOR常量定義在 include/drm/drm_accel.h 中#define ACCEL_MAJOR 261注意它放在include/drm/而非include/uapi/——該 major 號是內(nèi)核內(nèi)部約定用戶空間通過設(shè)備節(jié)點路徑訪問不需要在 uAPI 頭文件中聲明。3.2 命名約定的源碼實現(xiàn)devnode 回調(diào)/dev/accel/accel*這一目錄結(jié)構(gòu)并非 udev 規(guī)則而是由內(nèi)核類class的devnode回調(diào)直接生成的。drivers/accel/drm_accel.c 中static char *accel_devnode(const struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, accel/%s, dev_name(dev)); } static const struct class accel_class { .name accel, .devnode accel_devnode, };即設(shè)備節(jié)點路徑被硬編碼為accel/設(shè)備名而設(shè)備名本身按約定是accel0、accel1……最終得到/dev/accel/accel0這樣的節(jié)點sysfs 側(cè)由class_register(accel_class)產(chǎn)生/sys/class/accel/accel*/。3.3 字符設(shè)備注冊stub fops 與按需切換accel_core_init()在 DRM 核心初始化階段被調(diào)用錯誤清理由drm_core_exit()轉(zhuǎn)調(diào)accel_core_exit()完成核心動作是把 major 261 注冊為一個“stub”字符設(shè)備int __init accel_core_init(void) { int ret; ret accel_sysfs_init(); ... ret register_chrdev(ACCEL_MAJOR, accel, accel_stub_fops); ... }其中accel_stub_fops只有一個真正的openstatic int accel_stub_open(struct inode *inode, struct file *filp) { const struct file_operations *new_fops; struct drm_minor *minor; ... minor drm_minor_acquire(accel_minors_xa, iminor(inode)); ... new_fops fops_get(minor-dev-driver-fops); ... replace_fops(filp, new_fops); if (filp-f_op-open) err filp-f_op-open(inode, filp); ... }從源碼結(jié)構(gòu)看其工作方式是所有 accel 設(shè)備共用一個已注冊的 major文件打開時先根據(jù) inode 的minor 號從accel_minors_xaDEFINE_XARRAY_ALLOC(accel_minors_xa)定義的 xarray查找到對應(yīng)的drm_minor再將該file的fops替換為具體驅(qū)動的 fopsreplace_fops最后調(diào)用驅(qū)動的open。這與 DRM 自身的drm_stub_open機制完全同構(gòu)——再次印證“accel 設(shè)備就是一種新的 DRM 設(shè)備類型”。minor 號與設(shè)備實例的綁定則發(fā)生在設(shè)備實例化時void accel_set_device_instance_params(struct device *kdev, int index) { kdev-devt MKDEV(ACCEL_MAJOR, index); kdev-class accel_class; kdev-type accel_sysfs_device_minor; }該函數(shù)用MKDEV(261, index)組合出 devt并把設(shè)備實例掛到accelsysfs 類/sys/class/accel/accel*之下。3.4 公共 debugfs 節(jié)點框架還為每個加速器創(chuàng)建了公共 debugfs 文件位于/sys/kernel/debug/accel/*/下實現(xiàn)于accel_debugfs_register()static const struct drm_info_list accel_debugfs_list[] { {name, accel_name_info, 0} }; void accel_debugfs_register(struct drm_device *dev) { struct drm_minor *minor dev-accel; minor-debugfs_root dev-debugfs_root; drm_debugfs_create_files(accel_debugfs_list, ACCEL_DEBUGFS_ENTRIES, dev-debugfs_root, minor); }公共節(jié)點name會打印驅(qū)動名、底層設(shè)備名、master unique 與設(shè)備 unique 信息便于在 debugfs 中識別設(shè)備歸屬具體驅(qū)動可在此基礎(chǔ)上追加自己的調(diào)試節(jié)點。4. Getting Started驅(qū)動接入 accel 框架的兩處改動文檔“Getting Started”一節(jié)給出了驅(qū)動接入清單這里完整繼承并結(jié)合源碼逐條展開。4.0 前置先讀 DRM 文檔文檔明確要求首先閱讀 DRM 文檔Documentation/gpu/index.rst——它不僅講解如何編寫一個新的 DRM 驅(qū)動還包含貢獻流程、行為準則Code of Conduct、編碼與文檔風格這些都同樣適用于 accel 子系統(tǒng)。因為 accel 驅(qū)動在機制上就是一個 DRM 驅(qū)動所有drm_driver回調(diào)open/lastclose、GEM 回調(diào)、dumb系列等的語義完全一致。4.1 改動一設(shè)置DRIVER_COMPUTE_ACCEL特性標志在你的drm_driver.driver_features字段中加入DRIVER_COMPUTE_ACCEL。該標志定義在 include/drm/drm_drv.h/** * DRIVER_COMPUTE_ACCEL: * * Driver supports compute acceleration devices. This flag is mutually exclusive with * DRIVER_RENDER and DRIVER_MODESET. Devices that support both graphics and compute * acceleration should be handled by two drivers that are connected using auxiliary bus. */ DRIVER_COMPUTE_ACCEL BIT(7),兩個關(guān)鍵約束與文檔表述一致互斥性DRIVER_COMPUTE_ACCEL與DRIVER_RENDER、DRIVER_MODESET互斥。同一個drm_device不能同時聲明“渲染/顯示”與“計算加速”身份這是用戶空間隔離第 3 節(jié)在驅(qū)動側(cè)的強制點圖形計算雙能力設(shè)備的解法若硬件既需要暴露圖形設(shè)備文件又需要暴露計算設(shè)備文件應(yīng)當由兩個驅(qū)動分別處理并通過auxiliary bus輔助總線框架把二者連接起來——典型場景如 GPU 內(nèi)嵌的算力 IP 塊。4.2 改動二使用accel_open()或DEFINE_DRM_ACCEL_FOPS把驅(qū)動fops結(jié)構(gòu)中的open回調(diào)改為accel_open()。drivers/accel/drm_accel.c 中的accel_open文檔注釋明確要求“drivers must use it as their file_operations.open method”其實現(xiàn)流程為int accel_open(struct inode *inode, struct file *filp) { struct drm_device *dev; struct drm_minor *minor; int retcode; minor drm_minor_acquire(accel_minors_xa, iminor(inode)); if (IS_ERR(minor)) return PTR_ERR(minor); dev minor-dev; atomic_fetch_inc(dev-open_count); /* share address_space across all char-devs of a single device */ filp-f_mapping dev-anon_inode-i_mapping; retcode drm_open_helper(filp, minor); if (retcode) goto err_undo; return 0; ... } EXPORT_SYMBOL_GPL(accel_open);可以看到它完成三件事按 minor 號在accel_minors_xa中定位drm_minor、遞增設(shè)備打開計數(shù)、復(fù)用設(shè)備級 anon_inode 的address_space并交由drm_open_helper()完成 per-file 資源實例化與drm_driver.open回調(diào)。更省事的方式是使用DEFINE_DRM_ACCEL_FOPS宏定義于 include/drm/drm_accel.h一次性生成整個 fops 結(jié)構(gòu)#define DRM_ACCEL_FOPS \ .open accel_open,\ .release drm_release,\ .unlocked_ioctl drm_ioctl,\ .compat_ioctl drm_compat_ioctl,\ .poll drm_poll,\ .read drm_read,\ .llseek noop_llseek, \ .mmap drm_gem_mmap, \ .fop_flags FOP_UNSIGNED_OFFSET #define DEFINE_DRM_ACCEL_FOPS(name) \ static const struct file_operations name { \ .owner THIS_MODULE, \ DRM_ACCEL_FOPS, \ }從源碼結(jié)構(gòu)看DRM_ACCEL_FOPS與DRM_FOPS的字段一一對應(yīng)唯一區(qū)別是open從drm_open換成了accel_open。宏頭部的內(nèi)核文檔注釋還特別提醒生成的結(jié)構(gòu)體已隱含static且內(nèi)部引用THIS_MODULE因此不能在多個驅(qū)動間共享——每個驅(qū)動必須各自DEFINE_DRM_ACCEL_FOPS(自己的名字)后賦給drm_driver.fops。于是驅(qū)動的接入形態(tài)概括為drv-driver_features DRIVER_COMPUTE_ACCELDEFINE_DRM_ACCEL_FOPS(accel_fops)然后drv-fops accel_fops其余回調(diào)GEM、open/lastclose、命令提交等按常規(guī) DRM 驅(qū)動編寫參見 Documentation/gpu/index.rst。5. 框架核心代碼導(dǎo)讀drivers/accel/drm_accel.cdrivers/accel/drm_accel.c 全文約 210 行是 accel 子系統(tǒng)除各設(shè)備驅(qū)動外的全部框架代碼核心構(gòu)件一覽構(gòu)件作用accel_minors_xaxarray保存 minor 號 →drm_minor的全局映射accel_stub_open/accel_open均通過它定位設(shè)備accel_classclass創(chuàng)建/sys/class/accel/devnode accel_devnode使設(shè)備節(jié)點落在/dev/accel/目錄accel_devnode()返回accel/設(shè)備名形式的節(jié)點路徑accel_core_init()/accel_core_exit()注冊/注銷 major 261 的字符設(shè)備與 accel class由 DRM 核心的 init/exit 鏈路統(tǒng)一驅(qū)動accel_set_device_instance_params()為設(shè)備實例設(shè)置MKDEV(ACCEL_MAJOR, index)與 class/typeaccel_open()驅(qū)動必須使用的fops-open實現(xiàn)EXPORT_SYMBOL_GPLaccel_stub_open()字符設(shè)備統(tǒng)一入口按 minor 切換 fopsaccel_debugfs_register()創(chuàng)建公共 debugfsname節(jié)點從源碼結(jié)構(gòu)看整個框架不引入任何新的內(nèi)存管理或提交隊列機制——這些都直接復(fù)用 DRM/GEM/syncobj 基礎(chǔ)設(shè)施框架自身只負責“身份”major 號、命名空間、minor 路由和公共調(diào)試入口。這也是文檔中“accel 層提供 a common set of functionality”的具體所指。6. 適用前提與限制小結(jié)適用前提設(shè)備屬于計算加速器類別含但不限于 ML/DL 加速且驅(qū)動愿意按 DRM 驅(qū)動的形態(tài)編寫drm_driver GEM 自有 ioctl/提交接口。限制與約束CONFIG_DRM_ACCEL依賴CONFIG_DRMDRIVER_COMPUTE_ACCEL與DRIVER_RENDER/DRIVER_MODESET互斥圖形計算混合設(shè)備需借助 auxiliary bus 拆成兩個驅(qū)動DEFINE_DRM_ACCEL_FOPS生成的 fops 因THIS_MODULE而不可跨驅(qū)動共享用戶空間看到的設(shè)備節(jié)點固定為/dev/accel/accel*major 261圖形用戶空間軟件棧不會將其識別為 GPU 渲染設(shè)備。7. 延伸閱讀Documentation/accel/index.rstaccel 文檔索引另含amdxdna、qaic、rocket等具體驅(qū)動的文檔入口可與 drivers/accel/ 下的驅(qū)動實現(xiàn)對照閱讀Documentation/gpu/index.rstDRM 驅(qū)動開發(fā)、貢獻流程與編碼風格原文檔將其列為 accel 驅(qū)動開發(fā)者的必讀前置文檔drivers/accel/Kconfig、drivers/accel/Makefile框架與已合入設(shè)備驅(qū)動的配置/構(gòu)建入口include/drm/drm_accel.h、include/drm/drm_drv.hACCEL_MAJOR、DEFINE_DRM_ACCEL_FOPS、DRIVER_COMPUTE_ACCEL等接口的權(quán)威定義該子系統(tǒng)的歷史討論可追溯至 Oded Gabbay 在 2022 年發(fā)起的新子系統(tǒng)方案討論與補丁集LKML 郵件線程以及 Dave Airlie 在 LPC 2022 Accelerators BOF 后的總結(jié)文章原文檔 introduction.rst 的“External References”一節(jié)列有對應(yīng)出處可作為背景閱讀。【免費下載鏈接】linuxLinux kernel source tree項目地址: https://gitcode.com/GitHub_Trending/li/linux創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考