第二章:DRM 框架概述:2.1.1 drm_driver — 驱动能力声明与回调表

第二章:DRM 框架概述:2.1.1 drm_driver — 驱动能力声明与回调表 2.1 设备模型速览介绍了drm_device一块 GPU 的运行时实例与drm_file一次 open 的客户端上下文。这两个是动态对象——设备随硬件、文件随进程。三大对象里还剩一个静态的drm_driver它不描述「某一块卡的状态」而是声明「这一类驱动能做什么、遇到各种事件该调哪个函数」。drm_driver确实是 drm 中的一等对象值得细看下它的字段分组、每个关键字段服务的业务以及它背后「每驱动 → 每对象 → 每文件」的回调演进设计。1. 定位一张 const 的能力表vtabledrm_driver定义在include/drm/drm_drv.h有三个本质特征静态、const每种驱动在编译期定义一个实例如amdgpu_kms_driver全程只读。每驱动一份而非每设备一份一台机器插两张 AMD 卡会有两个drm_device但它们的dev-driver指向同一个amdgpu_kms_driver。它是一张虚函数表vtable内容几乎全是「能力标志 回调函数指针 元信息」。DRM 核心在通用流程里回调这张表把「与硬件相关的动作」下沉给具体驱动——这正是 C 语言实现多态的标准手法。三者的分工可以一句话概括drm_driver说「这类设备能做什么」静态能力表drm_device是「某一块具体设备」每卡一份drm_file是「某进程的一次打开」每 open 一份。2. 字段分组struct drm_driver的字段按职责分为五组structdrm_driver{/* ① 能力声明 */u32 driver_features;// DRIVER_GEM / RENDER / SYNCOBJ / MODESET .../* ② 客户端生命周期回调 */int(*open)(structdrm_device*,structdrm_file*);// 每次 open 建 per-file 资源void(*postclose)(structdrm_device*,structdrm_file*);// close 时对称拆除/* ③ GEM / PRIME / dumb 回调 —— BO 的创建与共享入口 */structdrm_gem_object*(*gem_create_object)(structdrm_device*,size_t);structdrm_gem_object*(*gem_prime_import)(structdrm_device*,structdma_buf*);structdrm_gem_object*(*gem_prime_import_sg_table)(structdrm_device*,structdma_buf_attachment*,structsg_table*);int(*dumb_create)(structdrm_file*,structdrm_device*,structdrm_mode_create_dumb*);int(*dumb_map_offset)(structdrm_file*,structdrm_device*,uint32_thandle,uint64_t*offset);/* ④ 入口表字符设备 fops 驱动私有 ioctl 表 */conststructdrm_ioctl_desc*ioctls;intnum_ioctls;conststructfile_operations*fops;/* ⑤ 元信息 */intmajor,minor,patchlevel;char*name,*desc;void(*show_fdinfo)(structdrm_printer*,structdrm_file*);// 调试统计};① 能力声明driver_features是一组位标志DRM 核心据此决定「给这类设备开哪些子系统、建哪些设备节点」。② 生命周期回调open/postclose是驱动介入「一次 open」的唯二钩子——per-file 的一切VM、上下文、记账都在这里建与拆。③ GEM/PRIME/dumb 回调BO 的分配与跨进程共享的驱动侧落点。④ 入口表fops是标准字符设备操作表open/ioctl/mmap/...ioctls[]是驱动私有 ioctl 的分发表。用户态所有请求都从这两张表进内核。⑤ 元信息namelsmod/dmesg/fdinfo里看到的驱动名、版本号等。3. 字段对应的功能或者业务drm_driver里几乎每个字段都是某后续章节的入口。读到后面章节遇到某个能力或回调时回头看这张表就知道它「从哪里被打开」字段 / 设计关联章节关联点driver_features: DRIVER_GEM第三章 GEM启用 GEM 子系统GEM_CREATE等 ioctl 才生效driver_features: DRIVER_RENDER本章 §4 节点创建renderD*节点compute/渲染的入口driver_features: DRIVER_SYNCOBJ[_TIMELINE]第六章同步启用 syncobj 及其 timeline 模式6.4.2driver_features: DRIVER_MODESET / ATOMIC显示路径边缘KMS 显示本专栏不展开open/postclose第七/八/九章amdgpu 在此建/拆amdgpu_fprivVM、ctx_mgrgem_create_object第三章 / 5.3.2GEM 对象构造钩子shmem/cma helper 用amdgpu 走私有路径gem_prime_import[_sg_table]第五章 5.3.1dma-buf 导入为 GEM 对象的驱动侧落点dumb_create/dumb_map_offset显示路径边缘简单显示 BO禁止用于渲染加速ioctls[] / num_ioctls第八章命令提交 / 各章amdgpu_cs_ioctl、GEM_CREATE等的分发表fopsdrm_gem_mmap3.4 vma_offset_managermmap 经 fops 进入落到伪 offset 机制show_fdinfo调试/proc/pid/fdinfo的 GPU 用量统计一句话driver_features决定「开哪些子系统」回调表决定「每个动作调谁」。后续每一章的功能追到根上都对应这张表里的某一位或某个回调。4. 设计洞察回调从「每驱动」到「每对象」再到「每文件」drm_driver里的 GEM/PRIME 回调藏着 DRM 一条清晰的演进线索——回调的归属粒度不断细化粒度细化运行时状态每驱动 vtabledrm_driver.gem_*/prime_*每对象 vtabledrm_gem_object_funcs每文件私有drm_file.driver_priv每驱动drm_driver早期 GEM 的分配、释放、mmap、export 等回调全挂在drm_driver上是「每种驱动一份」的粗粒度实现如历史上的gem_free_object。每对象drm_gem_object_funcs后来这些回调下沉到每个 GEM 对象详见 3.2.2粒度更细、更符合「对象自带行为」的直觉drm_driver只保留少数「构造类」钩子gem_create_object、gem_prime_import_sg_table——因为对象还没造出来构造行为无处可挂只能留在驱动级。每文件driver_priv而「进程私有的运行时状态」VM、上下文既不属于驱动也不属于对象挂在drm_file.driver_priv上由drm_driver.open创建。这条「静态能力driver→ 对象行为object_funcs→ 会话状态driver_priv」的三级划分是理解 DRM 回调体系的一把钥匙看到一个回调先问它该属于哪一级就知道它为什么在那里。5. amdgpu 实例amdgpu_kms_driveramdgpu 的drm_driver实例定义在drivers/gpu/drm/amd/amdgpu/amdgpu_drv.cstaticconststructdrm_driveramdgpu_kms_driver{.driver_featuresDRIVER_ATOMIC|DRIVER_GEM|DRIVER_RENDER|DRIVER_MODESET|DRIVER_SYNCOBJ|DRIVER_SYNCOBJ_TIMELINE,.openamdgpu_driver_open_kms,// ② 建 amdgpu_fprivVM ctx_mgr.postcloseamdgpu_driver_postclose_kms,// ② 对称拆除.ioctlsamdgpu_ioctls_kms,// ④ 驱动私有 ioctl 表.num_ioctlsARRAY_SIZE(amdgpu_ioctls_kms),.fopsamdgpu_driver_kms_fops,// ④ 字符设备入口.dumb_createamdgpu_mode_dumb_create,.dumb_map_offsetamdgpu_mode_dumb_mmap,.gem_prime_importamdgpu_gem_prime_import,// ③ dma-buf 导入.show_fdinfoamdgpu_show_fdinfo,.nameDRIVER_NAME,.descDRIVER_DESC,// ⑤ amdgpu.majorKMS_DRIVER_MAJOR,...};几处值得对照本文的点能力位amdgpu 开了GEM | RENDER | SYNCOBJ | SYNCOBJ_TIMELINE——这正是它支持 BO 管理、render 节点、显式同步与 timeline semaphore 的总开关。open amdgpu_driver_open_kms每次 open 在此分配amdgpu_fpriv创建 per-file 的amdgpu_vmGPU 页表与ctx_mgr——这就是 2.1 §3 讲的「不同进程有隔离的 GPU 地址空间」的源头。未设gem_create_objectamdgpu 的 BO 走自己的 TTM 分配路径不用 shmem/cma helper因此这个「构造钩子」留空而panfrost、lima这类 shmem 驱动才会设它见 5.3.2。6. 三者如何被串起来drm_driver不孤立存在它通过两条路径与drm_device、drm_file联动构成一次完整请求dev-driver指针每个drm_device都持有指向 driver 的指针。DRM 核心处理 ioctl 时用dev-driver-ioctls[]查表分发处理 open 时调dev-driver-open()。回调签名(dev, data, file_priv)几乎每个 ioctl 回调都同时收到drm_device与drm_file——三者在这里齐聚driver 决定「调哪个回调」device 提供「哪块硬件」file 提供「哪个进程上下文」。这三者的基数与生命周期关系driver 1:N device、device 1:N file以及一次 open→ioctl→close 如何贯穿在 2.1 的「三者关系」一节集中展开此处不再重复。7. 小结drm_driver是一张静态 const 的能力表vtable每种驱动一份声明「这类设备能做什么、事件来了调谁」。五组字段能力声明driver_features、生命周期回调open/postclose、GEM/PRIME/dumb 回调、入口表fops/ioctls、元信息。它是后续各章的入口开关某个功能能不能用追根到底是driver_features的某一位或某个回调是否设置。设计洞察GEM 回调沿「每驱动 → 每对象 → 每文件」三级细化看到一个回调先判断它属于哪一级就理解了它的归属。