news 2026/8/20 12:09:31

第九章:GPUVM:drm_gpuvm_ops--驱动需要实现的回调,分组与职责

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第九章:GPUVM:drm_gpuvm_ops--驱动需要实现的回调,分组与职责

前言

drm_gpuvm是 DRM 里的「GPU 地址空间管理器」,替驱动维护整段 GPU 虚拟地址空间。它遵循一条贯穿整个 DRM 子系统的设计原则:框架只实现与硬件无关的通用逻辑,凡是涉及具体硬件行为、驱动私有内存布局的动作,都通过struct drm_gpuvm_ops的回调交给驱动完成。这个「机制与策略分离」的取向,在前几章的设计里也反复出现。

这篇把drm_gpuvm_ops的 9 个回调讲清楚:

  1. 这 9 个回调怎么分组、每组负责什么;
  2. 为什么框架不亲自做这些事,而是交给驱动。

按「服务谁」归类,这 9 个回调恰好是三组,本文按从对象生命周期到地址空间落地的顺序,分组讲清楚。


1. 9 个回调的全景

structdrm_gpuvm_ops{/* 组一:对象生命周期 & 驻留 */void(*vm_free)(structdrm_gpuvm*gpuvm);structdrm_gpuvm_bo*(*vm_bo_alloc)(void);void(*vm_bo_free)(structdrm_gpuvm_bo*vm_bo);int(*vm_bo_validate)(structdrm_gpuvm_bo*vm_bo,structdrm_exec*exec);/* 组二:op 内存分配 */structdrm_gpuva_op*(*op_alloc)(void);void(*op_free)(structdrm_gpuva_op*op);/* 组三:地址空间变更的落地 */int(*sm_step_map)(structdrm_gpuva_op*op,void*priv);int(*sm_step_remap)(structdrm_gpuva_op*op,void*priv);int(*sm_step_unmap)(structdrm_gpuva_op*op,void*priv);};
分组回调服务对象
一、对象生命周期 & 驻留vm_freevm_bo_alloc/vm_bo_freevm_bo_validateGPUVM / BO 对象本身
二、op 内存分配op_alloc/op_free描述地址空间变更的drm_gpuva_op
三、地址空间变更落地sm_step_map/sm_step_remap/sm_step_unmap每一步的页表插入 / 拆分 / 删除

下面按这个顺序逐组说清职责。


2. 组一:对象生命周期 & 驻留管理

这一组管的是 GPUVM 和 BO 这两类对象本身的「生老病死」与「显存换入换出」,是整套回调里最基础、也最先被用到的。

回调触发点用途可选性
vm_freedrm_gpuvm最后一个引用被丢弃释放整个 VM强制
vm_bo_alloc/vm_bo_free分配 / 释放drm_gpuvm_bovm_bo是「GEM 对象 ↔ VM」的连接件可选
vm_bo_validatedrm_gpuvm_validate()提交前把被换出(evicted)的 BO 重新验证回显存用到才需

几个要点:

  • vm_free是整个 ops 里唯一强制的回调。框架在引用归零时会drm_WARN_ON(!ops->vm_free),然后调ops->vm_free(gpuvm)。因为drm_gpuvm通常内嵌在驱动更大的结构体里,框架只拿到内嵌字段的指针,根本不知道该怎么释放外层对象。

  • vm_bo_alloc/vm_bo_free定制vm_bo的内存布局。drm_gpuvm_bo是连接一个 GEM 对象与一个 VM 的中间结构,很多驱动想把它内嵌进自己的结构体,于是框架分配时先看驱动有没有实现:

    if(ops&&ops->vm_bo_alloc)vm_bo=ops->vm_bo_alloc();elsevm_bo=kzalloc(sizeof(*vm_bo),GFP_KERNEL);

    不实现就走默认kzalloc,实现了就用驱动定制版。

  • vm_bo_validate是驻留路径。它通常内部调用驱动版的ttm_bo_validate(),把被驱逐的 BO 搬回显存。这管的是「物理显存驻留」,和「虚拟地址布局」是正交的两件事。


3. 组二:op 列表的内存分配配套

op_alloc/op_free只做一件小事:分配和释放drm_gpuva_op

drm_gpuva_op是框架描述「一次地址空间变更需要哪些步骤」的数据结构。和vm_bo同理,很多驱动希望把drm_gpuva_op内嵌进自己的结构体里携带私有字段,于是框架在需要分配 op 时先看驱动有没有实现op_alloc,没有就用默认kzalloc

这两个回调也是可选的,纯粹是内存布局定制,不涉及任何页表语义。


4. 组三:地址空间变更的「落地三件套」

这三个是把「地址空间该怎么变」真正写进驱动页表的回调。框架内部会遍历地址空间、算出一次请求需要做哪些插入、拆分、删除,然后逐步回调给驱动落地:

回调语义动作
sm_step_map插入一条新映射
sm_step_remap把一条已有映射拆开(原映射被新请求部分覆盖时)
sm_step_unmap删除一条已有映射

一个容易忽略的点:这三步不是「一个请求只触发一步」。一条新映射若覆盖了旧映射,框架必须先 remap / unmap 掉旧的,再 map 新的,因此一次请求可能连续回调好几步。

框架对这三者有强制要求,入口会检查回调是否齐全:

if(unlikely(!(ops&&ops->sm_step_map&&ops->sm_step_remap&&ops->sm_step_unmap)))return-EINVAL;

也就是说:要用框架的地址空间变更引擎,就必须提供这组落地回调——框架只出「该做哪些步骤」的决策,驱动出「怎么写进硬件页表」的执行。


5. 为什么框架不自己做,而是交给驱动

这是本文的核心问题。框架明明已经算出了「该做哪些步骤」,为什么不干脆把页表也一起改了?答案可以归纳成四条边界。

5.1 硬件差异:页表格式框架根本不认识

不同 GPU 的页表结构、页大小、权限位编码、TLB 失效方式各不相同(AMD 的 GPUVM、Intel、Nouveau、Panthor 各有各的 MMU)。框架若要亲自写页表,就得内置所有厂商的 MMU 知识——这既不现实,也违背分层设计。

所以框架只做厂商无关的部分:地址区间的 split/merge 决策(这部分逻辑对所有 GPU 都一样);把厂商相关的落地动作(sm_step_*)留给驱动。这是最经典的「机制与策略分离」。

5.2 内存布局:对象由驱动拥有,框架不知如何分配/释放

drm_gpuvmdrm_gpuvm_bodrm_gpuva_op在实际驱动里几乎总是内嵌在更大的驱动私有结构体中。框架手里只有一个内嵌字段的指针,无法知道外层结构体的大小、也无法知道额外字段该怎么初始化和回收。

这正是vm_freevm_bo_alloc/freeop_alloc/free存在的原因:谁分配、谁定义布局,谁就得负责释放。框架只在「需要一个对象」和「对象该没了」的时机点回调,具体怎么分配/释放由拥有者决定。

5.3 时机与上下文:只有驱动知道何时真正写硬件

改页表往往不能立刻同步执行,而要挂到 fence、排进 DMA/SDMA 队列、和调度器与 dma_resv 锁协同。什么时候刷 TLB、是否要等某个 fence signalled、批处理还是逐条提交——这些都是驱动的调度语义。

框架把sm_step_*设计成「回调 + 驱动传入的priv指针」,本质是把执行时机的控制权交还给驱动:框架给你一步步的「要做什么」,你自己决定「什么时候、以什么并发方式做」。

5.4 驻留是驱动的独立子系统

vm_bo_validate背后是 TTM/BO 的驱逐与回迁体系,这套东西和地址空间管理是正交的两个子系统。框架没有理由、也没有能力去替驱动决定一个 BO 该不该被搬回显存、搬到哪个内存域。它只在drm_gpuvm_validate()需要时,把「这个被驱逐的 BO 需要验证」这一信号回调出去。


6. 小结

  • drm_gpuvm_ops的 9 个回调,按职责分三组:

    • 组一:对象生命周期 & 驻留vm_free(强制)、vm_bo_alloc/vm_bo_freevm_bo_validate——管 GPUVM/BO 对象的分配释放与显存驻留;
    • 组二:op 内存分配配套op_alloc/op_free——可选,定制drm_gpuva_op的内存布局;
    • 组三:地址空间变更落地sm_step_map/sm_step_remap/sm_step_unmap——框架强制要求,把每一步写进硬件页表。
  • 框架不自己动手,而是交给驱动,根本原因是机制与策略分离:框架掌握厂商无关的「算法」(对象生命周期时机、地址区间怎么切),驱动掌握厂商相关的「执行」(对象内存布局、页表长什么样、何时写硬件、BO 怎么驻留)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/20 12:05:26

3 步让红警 2 重新联机:IPXWrapper 完整配置指南与避坑清单

3 步让红警 2 重新联机:IPXWrapper 完整配置指南与避坑清单 【免费下载链接】ipxwrapper 项目地址: https://gitcode.com/gh_mirrors/ip/ipxwrapper 你是否经历过这样的场景:周末约好和朋友开黑《红色警戒 2》,双方连的是同一个 Wi-F…

作者头像 李华
网站建设 2026/8/20 11:59:06

SpringBoot校园招聘系统开发实践与架构设计

1. 项目背景与核心需求 校园招聘系统是高校就业指导工作中的重要数字化工具。作为计算机专业毕业设计的选题,基于SpringBoot的应届毕业生校园招聘系统具有典型的B/S架构特征和实际应用价值。这个选题之所以适合作为毕业设计,主要体现在三个方面&#xff…

作者头像 李华
网站建设 2026/8/20 11:58:36

AIGC内容安全实践:从技术原理到工程化风险防控

最近在技术社区里,一个看似“无厘头”的标题引起了我的注意:“[潮斯]看第3张图!不管过程结局是好的就对了!潮斯姐快猛吃!”。初看之下,这像极了社交媒体上某个粉丝圈内的“加密通话”,充满了圈地…

作者头像 李华
网站建设 2026/8/20 11:57:03

旧手机改造物联网节点:低成本替代GSM模块的完整方案

1. 项目概述:旧手机变身物联网核心 “别买GSM模块了,用你的旧手机!” 这个想法听起来有点天马行空,但当你手边堆着几台退役的安卓或苹果手机时,它就成了一个极具吸引力的技术方案。我们总在追求最新的硬件,…

作者头像 李华
网站建设 2026/8/20 11:50:55

软件代理监督实战:从目标对齐到过程监控的开发者新角色

1. 从“自动”到“自主”:当软件代理成为开发者的新同事 最近和几个团队聊,发现一个挺有意思的现象:大家不再只是讨论“自动化脚本”或者“CI/CD流水线”,而是开始频繁地提到“软件代理”。这词儿听起来有点科幻,但说白…

作者头像 李华