
本章目标把前三章的硬件概念实例、双队列、指针、命令映射到驱动的 C 数据结构上。读完你应该能画出amdgpu_sdma、amdgpu_sdma_instance、amdgpu_ring三者的包含关系并理解每个关键字段对应硬件的什么。4.1 三层包含关系先看全局SDMA 的数据结构是清晰的三层嵌套struct amdgpu_device └── struct amdgpu_sdma sdma; // ① 芯片级管所有 SDMA └── struct amdgpu_sdma_instance instance[16]; // ② 实例级一个物理引擎 ├── struct amdgpu_ring ring; // ③ 队列级GFX queue └── struct amdgpu_ring page; // ③ 队列级Page queueamdgpu_sdma整颗芯片上所有 SDMA 的总管挂在adev-sdma。amdgpu_sdma_instance一个物理 SDMA 引擎实例。amdgpu_ring一条命令队列。一个实例通常有两条ring和page。对照第 2 章这正是多实例 → 每实例两队列硬件模型的软件投影。4.2 实例级struct amdgpu_sdma_instance一个物理 SDMA 引擎的全部软件状态都在这里// amdgpu_sdma.hstructamdgpu_sdma_instance{/* SDMA firmware */conststructfirmware*fw;// 固件二进制uint32_tfw_version;uint32_tfeature_version;// 固件特性版本能力判断用structamdgpu_ringring;// ★ GFX queue通用拷贝/IBstructamdgpu_ringpage;// ★ Page queue页表更新专用bool burst_nop;// NOP 合并优化union{uint32_taid_id;// 所属 AID 分区大芯片uint32_txcc_id;// 所属 XCC 分区};structamdgpu_bo*sdma_fw_obj;// 固件加载到显存的 BOuint64_tsdma_fw_gpu_addr;uint32_t*sdma_fw_ptr;structmutexengine_reset_mutex;// 引擎复位串行化/* track guilty state of GFX and PAGE queues */bool gfx_guilty;// GFX 队列是否肇事挂了bool page_guilty;// Page 队列是否肇事conststructamdgpu_sdma_funcs*funcs;// ★ per-IP 复位等函数指针};关键字段解读ring/page本系列反复强调的一实例两队列就在这里落地。ring走SDMA0_GFX_*寄存器page走SDMA0_PAGE_*寄存器回顾第 2 章。fw系列SDMA 是有固件microcode的引擎启动时要把固件加载进去第 9 章。aid_id/xcc_id用union是因为不同芯片用不同的分区命名但语义都是这个实例属于哪个分区。gfx_guilty/page_guilty队列 hang 时用来标记是哪条队列出的事供引擎复位逻辑使用第 9、14 章。funcs指向 per-IP 的amdgpu_sdma_funcs这是函数指针解耦硬件差异的一个缩影第 5 章主角。4.2.1struct amdgpu_sdma_funcs实例级的钩子// amdgpu_sdma.hstructamdgpu_sdma_funcs{int(*stop_kernel_queue)(structamdgpu_ring*ring);int(*start_kernel_queue)(structamdgpu_ring*ring);int(*soft_reset_kernel_queue)(structamdgpu_device*adev,u32 instance_id);};这三个钩子服务于队列停止/启动/软复位是引擎级错误恢复reset的基础设施。不同硬件代实现不同因此做成函数指针。4.3 芯片级struct amdgpu_sdma整颗芯片所有 SDMA 的总控// amdgpu_sdma.hstructamdgpu_sdma{structamdgpu_sdma_instanceinstance[AMDGPU_MAX_SDMA_INSTANCES];// 实例数组最多 16/* 各类中断源 */structamdgpu_irq_srctrap_irq;// ★ TRAP任务完成structamdgpu_irq_srcillegal_inst_irq;// 非法指令structamdgpu_irq_srcfence_irq;structamdgpu_irq_srcecc_irq;// ECC/RASstructamdgpu_irq_srcvm_hole_irq;// 访问未映射地址structamdgpu_irq_srcdoorbell_invalid_irq;structamdgpu_irq_srcpool_timeout_irq;structamdgpu_irq_srcsrbm_write_irq;structamdgpu_irq_srcctxt_empty_irq;intnum_instances;// ★ 实际启用几个实例uint32_tsdma_mask;// ★ 可用实例位图union{intnum_inst_per_aid;// 每个 AID 分区几个实例intnum_inst_per_xcc;};uint32_tsrbm_soft_reset;bool has_page_queue;// ★ 本硬件是否启用 page 队列structras_common_if*ras_if;// RAS 接入structamdgpu_sdma_ras*ras;uint32_t*ip_dump;// 调试寄存器 dump 缓冲uint32_tsupported_reset;// 支持的复位类型structlist_headreset_callback_list;bool no_user_submission;bool disable_uq;// 是否禁用 user queuevoid(*get_csa_info)(structamdgpu_device*adev,structamdgpu_sdma_csa_info*csa_info);};关键字段解读instance[16]num_instancessdma_mask第 2 章多实例的落地。数组是静态最大实际用几个看num_instances哪几个可用看sdma_mask位图。宏NUM_SDMA(x) hweight32(x)就是数位图里有几个 1。has_page_queue决定本代硬件是否启用 page 队列的总开关。不为真时页表更新也走ring。这个字段在sw_init里被读到第 7 章。中断源一大簇对应第 2 章说的多种中断trap_irq最常用。ras/ras_if把 SDMA 接入 RASECC 错误上报与恢复框架第 9 章。ip_dumphang 排查时 dump 一批寄存器到这里第 14 章。4.4 干活能力的抽象amdgpu_buffer_funcsamdgpu_sdma.h里还定义了一个看似不属于 SDMA、实则由 SDMA 实现的接口——搬运能力// amdgpu_sdma.h/* * Provided by hw blocks that can move/clear data. e.g., gfx or sdma * But currently, we use sdma to move data. */structamdgpu_buffer_funcs{uint32_tcopy_max_bytes;// 单次拷贝最大字节数unsignedcopy_num_dw;// 每次拷贝命令占几个 dwordvoid(*emit_copy_buffer)(structamdgpu_ib*ib,uint64_tsrc,uint64_tdst,uint32_tbyte_count,uint32_tcopy_flags);// 发拷贝命令uint32_tfill_max_bytes;unsignedfill_num_dw;void(*emit_fill_buffer)(structamdgpu_ib*ib,uint32_tsrc_data,uint64_tdst,uint32_tbyte_count);// 发填充命令};注意注释这个接口理论上 GFX 也能提供但当前用 SDMA 来搬数据。它挂在adev-mman.buffer_funcs被 TTM 迁移路径调用第 11 章。配套两个宏#defineamdgpu_emit_copy_buffer(adev,ib,s,d,b,t)\(adev)-mman.buffer_funcs-emit_copy_buffer((ib),(s),(d),(b),(t))#defineamdgpu_emit_fill_buffer(adev,ib,s,d,b)\(adev)-mman.buffer_funcs-emit_fill_buffer((ib),(s),(d),(b))这里第一次看到 amdgpu 典型的funcs 接口 宏包装模式上层不直接调具体硬件函数而是通过函数指针表间接调用。第 5 章会系统讲这套解耦机制。4.5 RAS 相关amdgpu_sdma_ras与内存块枚举// amdgpu_sdma.hstructamdgpu_sdma_ras{structamdgpu_ras_block_objectras_block;// 把 SDMA 注册为一个 RAS block};enumamdgpu_sdma_ras_memory_id{// ECC 能覆盖的内部存储块AMDGPU_SDMA_MBANK_DATA_BUF01,...AMDGPU_SDMA_UCODE_BUF17,AMDGPU_SDMA_RB_CMD_BUF18,// ring buffer 命令缓冲AMDGPU_SDMA_IB_CMD_BUF19,// IB 命令缓冲...};入门阶段了解即可这个枚举列出了 SDMA 内部哪些 SRAM/FIFO 受 ECC 保护出错时用于定位。数据中心 GPU 才重点关注消费级可先跳过第 9 章简述。4.6 头文件里的通用 API 一览amdgpu_sdma.h末尾声明了一批通用与硬件无关函数它们的实现都在 amdgpu_sdma.c第 5 章详解// 从 ring 反查实例 / 索引structamdgpu_sdma_instance*amdgpu_sdma_get_instance_from_ring(structamdgpu_ring*ring);intamdgpu_sdma_get_index_from_ring(structamdgpu_ring*ring,uint32_t*index);// 上下文保存区地址抢占用uint64_tamdgpu_sdma_get_csa_mc_addr(structamdgpu_ring*ring,unsignedvmid);// 固件加载intamdgpu_sdma_init_microcode(structamdgpu_device*adev,u32 instance,bool duplicate);voidamdgpu_sdma_destroy_inst_ctx(structamdgpu_device*adev,bool duplicate);// RAS / ECCintamdgpu_sdma_ras_late_init(structamdgpu_device*adev,structras_common_if*ras_block);intamdgpu_sdma_process_ecc_irq(...);// 引擎复位、调试、sysfsintamdgpu_sdma_reset_engine(structamdgpu_device*adev,uint32_tinstance_id,bool...);voidamdgpu_debugfs_sdma_sched_mask_init(structamdgpu_device*adev);4.7 一张结构关系图adev └─ sdma : amdgpu_sdma ├─ instance[0] : amdgpu_sdma_instance │ ├─ fw / fw_version / feature_version ← 固件 │ ├─ ring : amdgpu_ring ← GFX queue ── SDMA0_GFX_* 寄存器 │ ├─ page : amdgpu_ring ← Page queue ── SDMA0_PAGE_* 寄存器 │ ├─ aid_id / xcc_id ← 分区归属 │ ├─ gfx_guilty / page_guilty ← 错误状态 │ └─ funcs : amdgpu_sdma_funcs* ← stop/start/soft_reset queue ├─ instance[1] ... ├─ num_instances / sdma_mask ← 用几个、哪几个 ├─ has_page_queue ← 是否启用 page 队列 ├─ trap_irq / ecc_irq / ... ← 中断源 └─ ras / ras_if ← RAS 接入 adev.mman.buffer_funcs : amdgpu_buffer_funcs* ← 由 SDMA 实现的拷贝/填充能力4.8 本章小结SDMA 数据结构是三层嵌套amdgpu_sdma芯片→amdgpu_sdma_instance实例→amdgpu_ring队列。实例里ringGFXpagePage两条队列是硬件一实例两队列的直接映射。芯片级用instance[]num_instancessdma_mask管多实例用has_page_queue决定是否启用 page 队列。funcs指针实例级amdgpu_sdma_funcs、搬运级amdgpu_buffer_funcs预示了下一章的核心主题函数指针解耦。中断源、RAS、固件字段分别对应任务通知、错误恢复、引擎启动后续章节各有展开。下一章预告我们已经看到多处funcs函数指针。第 5 章专门讲 amdgpu 的分层哲学——通用层定义是什么per-IP 层通过函数指针填入怎么做并巡览amdgpu_sdma.c里那些与硬件无关的通用 helper。