恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
第 3 章 SDMA 指令集:Packet 格式速览
首页
资讯中心
/
第 3 章 SDMA 指令集:Packet 格式速览
第 3 章 SDMA 指令集:Packet 格式速览
发布时间:2026/8/19 22:51:58
本章目标上一章说硬件只认命令流本章就来看下命令packet到底长什么样。不需要记忆全部字段我们抓住header opcode sub-opcode 参数这个统一骨架然后用本仓库里几个真实的 emit 函数看懂WRITE/INDIRECT/FENCE/TRAP/POLL_REGMEM这几个最常用的命令是怎么拼出来的。3.1 packet 的统一骨架SDMA 的每条命令都是若干个dword32 位拼起来的。第一个 dword 是header其余是这条命令的参数。header 里最关键的两个字段OPopcode主操作码决定这是哪一类命令写内存拷贝发 fence。SUB_OPsub-opcode子操作码在同一大类里再细分比如 WRITE 里再分线性写 / tiled 写。在代码里header 用一组宏拼装最典型的就是SDMA_PKT_HEADER_OP(...)// 一个 header 的通用形态SDMA_PKT_HEADER_OP(op)|SDMA_PKT_HEADER_SUB_OP(sub_op)|其它标志位驱动侧用amdgpu_ring_write(ring, dword)把一个个 dword 依次写进 ring buffer硬件就按顺序读出来解释执行。理解 packet本质就是理解每个 dword 放了什么。3.2 最小可验证例子WRITE写一个魔数理解 packet 的最佳入口是 ring 自检函数sdma_v4_0_ring_test_ring()。它干的事极简单用 SDMA 往一块内存写一个已知值0xDEADBEEF然后 CPU 去读读到了就说明引擎活着。// sdma_v4_0.c: sdma_v4_0_ring_test_ring()节选tmp0xCAFEDEAD;adev-wb.wb[index]cpu_to_le32(tmp);// 先把目标内存填成 0xCAFEDEADamdgpu_ring_alloc(ring,5);// 这条命令占 5 个 dwordamdgpu_ring_write(ring,SDMA_PKT_HEADER_OP(SDMA_OP_WRITE)|// dw0: headerSDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_WRITE_LINEAR));amdgpu_ring_write(ring,lower_32_bits(gpu_addr));// dw1: 目标地址低 32amdgpu_ring_write(ring,upper_32_bits(gpu_addr));// dw2: 目标地址高 32amdgpu_ring_write(ring,SDMA_PKT_WRITE_UNTILED_DW_3_COUNT(0));// dw3: 写多少countamdgpu_ring_write(ring,0xDEADBEEF);// dw4: 要写入的数据amdgpu_ring_commit(ring);// 提交推 WPTR 敲门把这 5 个 dword 排开看WRITE (LINEAR)packet 的结构一目了然dword内容说明dw0headerOPWRITE,SUB_OPWRITE_LINEARdw1dst addr lo目标 GPU 地址低 32 位dw2dst addr hi目标 GPU 地址高 32 位dw3count写入的 dword 数0 表示 1 个dw4data要写的值0xDEADBEEF执行后 CPU 轮询那块内存从0xCAFEDEAD变成0xDEADBEEF就算通过。这就是一条完整 SDMA 命令的最小闭环把它记牢后面再复杂的 packet 也是同一套路。3.3INDIRECT执行一个 IB间接缓冲区ring buffer 本身不大不适合放很长的命令流。真正干活的大命令流通常放在单独的IBIndirect Buffer里然后在 ring 里放一条INDIRECTpacket告诉硬件去那个地址执行一段命令。// sdma_v4_0.c: sdma_v4_0_ring_emit_ib()节选amdgpu_ring_write(ring,SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT)|// dw0: header vmidSDMA_PKT_INDIRECT_HEADER_VMID(vmid0xf));amdgpu_ring_write(ring,lower_32_bits(ib-gpu_addr)0xffffffe0);// dw1: IB 地址低32B 对齐amdgpu_ring_write(ring,upper_32_bits(ib-gpu_addr));// dw2: IB 地址高amdgpu_ring_write(ring,ib-length_dw);// dw3: IB 长度dwordamdgpu_ring_write(ring,0);// dw4/5: csa 等amdgpu_ring_write(ring,0);要点header 里带了VMID——说明这段 IB 在哪个虚拟地址空间里执行这是 GPU 虚拟内存隔离的一部分。IB 地址要求32 字节对齐 0xffffffe0。这就是ring → IB两级命令结构的硬件基础第 6 章会从软件角度再讲一遍。3.4FENCETRAP宣告我干完了一批命令执行完需要两件事① 写一个递增的序号seq到某个地址fence让别人能查询进度② 触发一个中断trap主动通知驱动。SDMA 把这两步分别用FENCE和TRAP两条 packet 完成// sdma_v4_0.c: sdma_v4_0_ring_emit_fence()节选/* ① 写 fence把 seq 写到 addr */amdgpu_ring_write(ring,SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));amdgpu_ring_write(ring,lower_32_bits(addr));// fence 地址低amdgpu_ring_write(ring,upper_32_bits(addr));// fence 地址高amdgpu_ring_write(ring,lower_32_bits(seq));// 序号/* 64 位 fence 时再写一遍高 32 位略*//* ② 触发中断TRAP */amdgpu_ring_write(ring,SDMA_PKT_HEADER_OP(SDMA_OP_TRAP));amdgpu_ring_write(ring,SDMA_PKT_TRAP_INT_CONTEXT_INT_CONTEXT(0));回顾第 2 章的硬件模型TRAP 触发的正是trap_irq驱动在中断里推进 fence、唤醒等待者。FENCE可查询TRAP主动通知就是 GPU 任务完成通知的标准组合拳。3.5POLL_REGMEM等待某个条件成立有时命令流需要等到某寄存器/内存等于某值再继续比如 HDP cache flush。这用POLL_REGMEM轮询寄存器或内存实现// sdma_v4_0.c: sdma_v4_0_wait_reg_mem()节选amdgpu_ring_write(ring,SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM)|SDMA_PKT_POLL_REGMEM_HEADER_HDP_FLUSH(hdp)|SDMA_PKT_POLL_REGMEM_HEADER_MEM_POLL(mem_space)|SDMA_PKT_POLL_REGMEM_HEADER_FUNC(3));/* 3 等于 */// ... 地址、reference期望值、mask、retry/interval ...它内建比较函数这里FUNC(3)表示、期望值、掩码和重试间隔硬件会自旋等待直到条件满足。emit_hdp_flush、emit_vm_flushTLB 失效等待都用它做同步。3.6 与页表相关的 opcodeCOPY与PTEPDE预告除了上面这些通用命令SDMA 还有专门服务页表更新的 opcode本章先点名第 12 章展开COPY批量拷贝vm_copy_pte用它把一批 PTE 从暂存区拷进页表。WRITE逐条写 PTE就是 3.2 那个 WRITEvm_write_pte会用到支持递增地址。PTEPDE页表专用vm_set_pte_pde用它对连续页表项做批量、带掩码的更新一条命令顶很多条 WRITE。这三条正是 SDMA 作为页表更新执行者的指令基础。3.7 常用 opcode 速查本章出现的opcode作用出现在SDMA_OP_WRITE往内存写数据test_ring、vm_write_pteSDMA_OP_COPY内存拷贝emit_copy_buffer、vm_copy_pteSDMA_OP_INDIRECT执行一个 IBemit_ibSDMA_OP_FENCE写 fence 序号emit_fenceSDMA_OP_TRAP触发中断emit_fenceSDMA_OP_POLL_REGMEM轮询等待条件hdp_flush、vm_flushSDMA_OP_PTEPDE批量更新连续页表项vm_set_pte_pde完整版见 附录 B 常用 SDMA opcode 速查表。3.8 本章小结SDMA 每条命令 headerOP SUB_OP 标志 若干参数 dword用amdgpu_ring_write逐 dword 写入 ring。WRITE3.2 的写魔数是理解 packet 的最小闭环务必吃透。INDIRECT把 ring 引到更大的IB去执行并携带 VMID。FENCE TRAP是任务完成通知的标准组合前者可查询、后者发中断。POLL_REGMEM用于命令流内的等待/同步。COPY/WRITE/PTEPDE是页表更新的指令基础为第 12 章埋下伏笔。下一章预告硬件三章到此结束。从第 4 章起进入软件层我们先总览 SDMA 在驱动里的数据结构——amdgpu_sdma_instance与amdgpu_sdma——看这些 packet、队列、指针在 C 结构体里是如何被组织起来的。