AMD KFD的BO设计分析系列6-3: res_cursor--BO物理内存资源的迭代器
这篇文章讲一下AMD中设计的amdgpu_res_cursor
。amdgpu_res_cursor
是 AMDGPU 驱动资源管理中的重要抽象,专为分块资源的遍历和操作而设计。
1. 背景与设计目的
在现代 GPU 驱动架构中,显存和系统内存的分配、管理、映射是高性能图形渲染和异构计算的基础。AMDGPU 驱动基于 TTM(Translation Table Manager)框架,采用多层次的资源管理器(如 VRAM 管理器、GTT 管理器)来管理物理内存资源。由于显存分配往往是分块(block)或分段(node)进行的,实际的物理资源可能由多个不连续的区间组成。
在进行页表填充、DMA 映射、数据清零等操作时,驱动需要遍历这些分块资源,并将其与虚拟地址空间进行映射。amdgpu_res_cursor
就是为此设计的一个通用游标(cursor)结构体和操作接口,方便在 VRAM/GTT/DOORBELL 等不同类型的资源分配器中遍历和操作分块资源。也可以看作物理内存资源集合的迭代器。
2. 结构体定义与成员功能
struct amdgpu_res_cursor {uint64_t start; // 当前块的物理起始地址uint64_t size; // 当前块的大小(字节)uint64_t remaining; // 剩余待遍历的总大小void *node; // 指向当前块(block/node)的指针uint32_t mem_type; // 当前资源类型(VRAM/GTT/DOORBELL)
};
-
start:当前遍历到的物理块的起始地址(以字节为单位),用于后续页表填充或数据操作。
-
size:当前块的大小,决定本次操作能覆盖的字节数。
-
remaining:本次遍历还剩下多少字节未处理,便于循环和终止条件判断。
-
node:指向当前物理块的结构体指针(如
drm_buddy_block
或drm_mm_node
),用于获取块的详细信息。 -
mem_type:资源类型,决定遍历和块处理的方式。常见值有 TTM_PL_VRAM、TTM_PL_TT、AMDGPU_PL_DOORBELL。
3. 核心操作接口与实现
3.1 初始化游标:amdgpu_res_first
static inline void amdgpu_res_first(struct ttm_resource *res,uint64_t start, uint64_t size,struct amdgpu_res_cursor *cur);
-
功能:初始化游标,准备遍历指定资源对象(如 VRAM/GTT)的分块区间。
-
实现思路:
-
判断资源类型(mem_type),选择合适的分块链表或节点数组。
-
跳过前面的块,定位到起始地址对应的块。
-
设置游标的 start、size、remaining、node 等成员,准备后续遍历。
-
VRAM场景
- 遍历
amdgpu_vram_mgr_resource
的blocks
链表,定位到起始块。 - 计算块内偏移,设置游标。
GTT/DOORBELL场景
- 遍历
ttm_range_mgr_node
的mm_nodes
数组,定位到起始节点。 - 计算节点内偏移,设置游标。
Fallback场景
- 如果资源类型不支持或资源为空,游标直接指向整个区间,node 设为 NULL。
3.2 游标前进:amdgpu_res_next
static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size);
-
功能:将游标向前移动指定字节数,自动跳转到下一个块或节点。
-
实现思路:
-
更新 remaining 和当前块的 size。
-
如果当前块还有剩余空间,则只移动 start 和 size。
-
如果当前块用完,则跳转到下一个块或节点,重新设置 start、size、node。
-
支持 VRAM、GTT、DOORBELL等多种资源类型。
-
3.3 块清零检测:amdgpu_res_cleared
static inline bool amdgpu_res_cleared(struct amdgpu_res_cursor *cur);
-
功能:检测当前块是否已经被清零(如分配时已初始化为0)。
-
实现思路:
-
仅支持 VRAM 类型,通过
amdgpu_vram_mgr_is_cleared
检查块状态。 -
其他类型默认返回 false。
-
4. 应用场景与示例
4.1 页表填充(PTE设置)
在 BO 映射到 GPU 虚拟地址空间时,驱动需要将物理块的地址填充到页表项(PTE),实现虚拟地址到物理地址的映射。由于 BO 可能由多个物理块组成,驱动可用 amdgpu_res_cursor
遍历所有块,逐块填充页表。
示例流程:
struct amdgpu_res_cursor cur;
amdgpu_res_first(res, start_offset, total_size, &cur);while (cur.remaining) {// 填充页表项,将 cur.start 映射到虚拟地址set_pte(vm, vaddr, cur.start, cur.size, flags);// 前进到下一个块amdgpu_res_next(&cur, cur.size);
}
4.2 DMA 映射与数据传输
在进行 DMA 操作(如显存清零、数据拷贝)时,驱动需要遍历所有物理块,将每个块的物理地址传递给 DMA 引擎。amdgpu_res_cursor
可用于高效遍历和分块操作。
示例流程:
struct amdgpu_res_cursor cur;
amdgpu_res_first(res, 0, bo_size, &cur);while (cur.remaining) {dma_map(cur.start, cur.size);amdgpu_res_next(&cur, cur.size);
}
4.3 块清零检测与优化
在分配显存时,部分块可能已被硬件清零,无需再次初始化。驱动可用 amdgpu_res_cleared
检查块状态,跳过已清零块,提升性能。
示例流程:
struct amdgpu_res_cursor cur;
amdgpu_res_first(res, 0, bo_size, &cur);while (cur.remaining) {if (!amdgpu_res_cleared(&cur))memset_io(cur.start, 0, cur.size);amdgpu_res_next(&cur, cur.size);
}
5. 总结
amdgpu_res_cursor
是对 TTM/AMDGPU 资源分块管理的进一步抽象,专注于遍历和操作分块资源。在涉及分块资源遍历的场景(如页表填充、DMA映射)优先使用 amdgpu_res_cursor
,避免手动循环和边界判断。优点总结如下:
-
统一抽象:用一个游标结构体和接口,统一遍历多种资源类型,简化驱动代码。
-
高效分块遍历:支持分块、分段资源的高效遍历,适应显存分配的实际需求。
-
灵活偏移与区间支持:支持任意起始偏移和区间大小,便于处理部分映射、分段操作等复杂场景。
-
自动跳转与终止:自动处理块跳转和终止条件,减少手动循环和边界判断。
-
扩展性强:可扩展支持更多资源类型和块属性(如清零、压缩等)。
看似该结构体没有特别之处,但结合前面文章AMD KFD的BO设计分析系列6-1: VRAM BO的显存分配分析中分配物理显存的blocks,会对该结构体的重要性有一个新的认识,在AMD VM中实现VMA到物理显存的映射时,就使用了这个cursor。
如有帮助,请三连:点赞、收藏、加关注。