恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
第 2 章 SDMA 硬件模型:队列、指针与 doorbell
首页
资讯中心
/
第 2 章 SDMA 硬件模型:队列、指针与 doorbell
第 2 章 SDMA 硬件模型:队列、指针与 doorbell
发布时间:2026/8/18 12:48:55
本章目标建立 SDMA 硬件侧的最小心智模型。我们不逐个寄存器地啃 datasheet只讲清楚四件事ring buffer 怎么工作、RPTR/WPTR 两个指针的分工、doorbell 如何通知硬件、以及一个实例两条队列和多实例的由来。这些是理解后续所有软件代码的物理基础。2.1 一切的核心ring buffer环形命令队列SDMA 硬件不接受函数调用它只认一样东西——命令流。驱动把要做的事编码成一串命令packet放进一块环形缓冲区ring buffer硬件从里面顺序取命令执行。上一张经典图示它是环形的写到末尾后回绕到开头用取模运算管理下标。驱动是生产者往里塞命令硬件是消费者从里取命令。生产和消费的进度各用一个指针来标记——这就是 RPTR 和 WPTR。2.2 两个指针RPTR 与 WPTR 的分工理解 ring 的关键是分清两个指针各归谁管指针全称谁负责推进含义RPTRRead Pointer硬件硬件已经读取/执行到哪里了WPTRWrite Pointer驱动驱动已经写入命令到哪里了工作规则驱动写完新命令后把 WPTR往前推告诉硬件这里有新活儿。硬件执行命令时把 RPTR往前追追到和 WPTR 相等就说明活儿干完了没新命令。RPTR WPTR⇒ 队列空闲WPTR领先RPTR⇒ 有待执行命令。在本仓库代码里的印证看 v4.0 的读指针实现RPTR 是硬件写在内存里、驱动只读的一个值// sdma_v4_0.c: sdma_v4_0_ring_get_rptr()staticuint64_tsdma_v4_0_ring_get_rptr(structamdgpu_ring*ring){u64*rptr((u64*)ring-rptr_cpu_addr);// 硬件把 rptr 写回这块内存return((*rptr)2);// 驱动直接读} 2是因为硬件里的指针以字节计而驱动用 dword4 字节为单位两者差一个移位换算。这个细节记住即可后面很多地方都有 2/ 2。2.3 doorbell驱动如何敲门通知硬件问题来了驱动把 WPTR 更新了硬件怎么知道总不能让硬件一直忙等着轮询吧。答案是doorbell门铃机制。doorbell 是一段特殊的 MMIO 地址驱动往里一写硬件立刻被叫醒去看新的 WPTR。相当于驱动放好菜后按一下传菜铃。看 v4.0 的写指针实现清楚地体现了这个两步动作// sdma_v4_0.c: sdma_v4_0_ring_set_wptr() doorbell 路径if(ring-use_doorbell){u64*wb(u64*)ring-wptr_cpu_addr;WRITE_ONCE(*wb,(ring-wptr2));// ① 把新 WPTR 写到 writeback 内存WDOORBELL64(ring-doorbell_index,ring-wptr2);// ② 敲门通知硬件}两条路径代码里set_wptr/get_wptr都有if (ring-use_doorbell) ... else ...doorbell 路径现代默认WPTR 放在一块 CPU/GPU 都能访问的 writeback 内存再通过WDOORBELL64敲门。快、开销小。MMIO 寄存器路径回退/老硬件直接写mmSDMA0_GFX_RB_WPTR/mmSDMA0_GFX_RB_WPTR_HI寄存器。}else{// 非 doorbell直接写寄存器WREG32_SDMA(ring-me,mmSDMA0_GFX_RB_WPTR,lower_32_bits(ring-wptr2));WREG32_SDMA(ring-me,mmSDMA0_GFX_RB_WPTR_HI,upper_32_bits(ring-wptr2));}use_doorbell是理解 SDMA 提交路径的一个高频开关第 8 章会再遇到它。2.4 一个实例两条队列GFX queue 与 Page queue这是 SDMA 硬件设计中一个极其重要、又容易忽略的点同一个 SDMA 引擎实例往往对外提供两条独立的 ring。GFX queuering通用队列处理拷贝、填充、间接缓冲区IB等一般 DMA 任务。Page queuepage专用于VM 页表更新的队列。为什么要分开核心是优先级隔离与互不阻塞页表更新往往是内存管理路径上的关键操作比如缺页恢复、迁移需要及时完成如果和大块数据拷贝挤在同一条队列里排队一个几十 MB 的拷贝就可能把紧急的页表更新堵在后面。分成两条独立队列后页表更新走自己的 page ring不受数据搬运的影响。这一点在数据结构里有直接体现第 4 章详述// amdgpu_sdma.h: struct amdgpu_sdma_instancestructamdgpu_ringring;// GFX queuestructamdgpu_ringpage;// Page queue并且硬件的两条队列有各自独立的寄存器组从 v4.0 的代码就能看到mmSDMA0_GFX_RB_WPTR和mmSDMA0_PAGE_RB_WPTR是两套// GFX queue 用 SDMA0_GFX_* 寄存器wptr|RREG32_SDMA(ring-me,mmSDMA0_GFX_RB_WPTR);// Page queue 用 SDMA0_PAGE_* 寄存器wptr|RREG32_SDMA(ring-me,mmSDMA0_PAGE_RB_WPTR);注意并非所有硬件都有 page queue。是否启用由adev-sdma.has_page_queue控制详见第 4、7 章。2.5 多实例multi-instance与分区现代大芯片上SDMA 不止一个引擎而是多个物理实例并存以提升总搬运带宽。驱动用一个数组来管理它们// amdgpu_sdma.h#defineAMDGPU_MAX_SDMA_INSTANCES16structamdgpu_sdma_instanceinstance[AMDGPU_MAX_SDMA_INSTANCES];intnum_instances;// 实际启用了几个uint32_tsdma_mask;// 哪些实例可用的位图消费级显卡通常 1~2 个实例。数据中心 GPU如 MI 系列实例数量多且和芯片的**分区partition**概念绑定。代码里instance结构中的aid_id/xcc_id就是标记这个实例属于哪个AIDActive IO Die或 XCCAccelerator Core Complex分区// amdgpu_sdma.h: struct amdgpu_sdma_instanceunion{uint32_taid_id;// 属于哪个 AID 分区uint32_txcc_id;// 属于哪个 XCC 分区};对入门理解而言你只需记住实例是物理引擎多实例是为了带宽和分区并行每个实例再分 GFX/Page 两条逻辑队列。2.6 硬件如何通知干完了中断任务执行完硬件需要告诉驱动。方式是中断IRQ。SDMA 有多种中断源在数据结构里一字排开// amdgpu_sdma.h: struct amdgpu_sdmastructamdgpu_irq_srctrap_irq;// 命令流里的 TRAP通常代表 fence 完成structamdgpu_irq_srcillegal_inst_irq;// 非法指令structamdgpu_irq_srcfence_irq;structamdgpu_irq_srcecc_irq;// ECC 错误RAS...其中最重要的是trap_irq驱动在命令流末尾放一个TRAPpacket硬件执行到它就发中断驱动据此知道这批命令做完了进而推进 fence、唤醒等待者。这条闭环在第 9 章展开。2.7 把硬件模型串起来一次搬运的硬件视角先用一张全景图把前面各节的部件多实例、双队列、RPTR/WPTR、doorbell、中断组织起来SDMA 硬件 (GPU)驱动侧 (CPU)SDMA instance 0 (物理引擎, aid_id/xcc_id)GFX queue (ring)rptr 写回内存, 驱动只读MMIO doorbell页表更新走独立队列执行 TRAP packet执行 TRAP packetPage queue (page, 仅 has_page_queue)ring buffer (页表更新专用)RPTRWPTR生产者: 写 packet 命令流推进 WPTRWDOORBELL64 敲门中断处理: 推进 fence / 唤醒等待者ring buffer 环形命令队列RPTR (硬件推进)WPTR (驱动推进)SDMA instance 1 ... N (多实例, 提升带宽)trap_irq 中断再看一次完整搬运在时间轴上的分步动作驱动侧 硬件侧 ────── ────── 1. 把命令写进 ring buffer 2. WPTR 前移写入 writeback 内存 3. WDOORBELL64 敲门 ───────────────────► 4. 被叫醒比较 RPTR/WPTR 5. 从 ring 取命令依次执行 6. 执行完把 RPTR 前移 7. 读 rptr_cpu_addr 得知进度 ◄────────── RPTR 写回内存 8. 遇到 TRAP packet 触发中断 9. 中断处理推进 fence唤醒等待者 ◄────── trap_irq这张图就是后面所有软件代码运转的底层剧本。你会发现第 8 章讲的emit_ib、emit_fence、set_wptr全都能在这张图里找到对应的一步。2.8 本章小结SDMA 硬件的核心是ring buffer RPTR/WPTR 双指针RPTR 归硬件、WPTR 归驱动。驱动通过doorbell敲门通知硬件有新命令老硬件回退到直接写 MMIO 寄存器。一个实例通常有两条队列GFX queuering通用和 Page queuepage页表专用分开是为了让紧急的页表更新不被大块拷贝阻塞。大芯片上有多实例并与 AID/XCC分区绑定用instance[]数组 sdma_mask管理。硬件通过中断尤其 trap_irq通知任务完成。下一章预告既然硬件只认命令流那命令packet长什么样下一章我们拆解 SDMA 的指令集——WRITE、COPY、FENCE、TRAP、INDIRECT、PTEPDE这些 opcode看一个最小命令流是如何拼出来的。