Linux内核5.15下AMD显卡休眠唤醒:BO驱逐流程与显存管理3个关键阶段
Linux内核5.15下AMD显卡休眠唤醒:BO驱逐流程与显存管理3个关键阶段
引言
在Linux系统中,显卡的休眠唤醒机制一直是驱动开发者关注的焦点。特别是对于AMD显卡而言,其显存管理机制在休眠唤醒过程中扮演着至关重要的角色。本文将深入剖析Linux内核5.15版本下AMD显卡的休眠唤醒流程,重点聚焦Buffer Object(BO)的驱逐机制以及显存管理的三个关键阶段。
对于内核开发者和驱动工程师来说,理解这一流程不仅有助于解决实际开发中遇到的休眠唤醒问题,更能为性能优化提供理论依据。我们将从技术细节入手,通过图解和代码分析,揭示BO在VRAM、GTT和系统内存之间的迁移路径,以及不同阶段驱逐操作的具体目的。
1. BO驱逐流程全景解析
1.1 BO在显存管理中的核心作用
Buffer Object(BO)是AMD显卡驱动中管理显存的基本单元,它封装了显存分配、映射和同步等核心功能。在休眠唤醒过程中,BO的状态迁移直接影响整个流程的成功率。
BO的主要属性包括:
- 内存域(domain):标识当前所处的内存区域(VRAM/GTT/系统内存)
- 驱逐优先级(eviction priority)
- 内存类型(可见显存/不可见显存)
- 引用计数
1.2 休眠过程中的两次驱逐调用
在休眠流程中,
radeon_bo_evict_vram
会被调用两次,每次都有不同的目的:
static int radeon_pmops_suspend(struct device *dev)
{
// 第一次驱逐:确保数据写回
radeon_bo_evict_vram(rdev);
radeon_fence_driver_force_completion(rdev);
// 第二次驱逐:确保数据保存
radeon_suspend(rdev);
radeon_bo_evict_vram(rdev);
}
第一次驱逐的关键任务:
- 将VRAM中的活跃数据迁移到安全位置
- 等待GPU完成所有未决操作
- 保存BIOS scratch寄存器等关键状态
第二次驱逐的核心目标:
- 释放所有剩余的VRAM资源
- 确保数据已持久化到系统内存或休眠镜像
- 为设备完全断电做准备
1.3 BO驱逐的TTM实现机制
BO驱逐最终通过TTM(Translation Table Maps)内存管理器实现,其核心流程如下:
int ttm_bo_evict_mm(struct ttm_bo_device *bdev, struct ttm_mem_type_manager *man)
{
list_for_each_entry(bo, &man->lru[i], lru) {
if (!bdev->driver->eviction_valuable(bo, place))
continue;
ttm_bo_evict(bo, interruptible, no_wait_gpu);
}
}
驱逐决策矩阵:
| BO位置 | 目标位置 | 条件判断 |
|---|---|---|
| 可见VRAM | 不可见VRAM | 不可见VRAM有足够空间 |
| 可见VRAM | GTT | 不可见VRAM空间不足 |
| 不可见VRAM | GTT | GTT有可用空间 |
| GTT | 系统内存 | GTT空间不足 |
2. 显存管理的三个关键阶段
2.1 预驱逐阶段(Pre-Eviction)
在正式驱逐前,驱动需要完成一系列准备工作:
-
显示输出处理 :
- 关闭所有显示输出(DRM_MODE_DPMS_OFF)
- Unpin桌面和鼠标相关的BO(保留fb BO)
-
硬件状态保存 :
radeon_save_bios_scratch_regs(rdev); evergreen_suspend(rdev); // ASIC特定挂起例程 -
中断禁用 :
- 关闭HPD(热插拔检测)中断
- 禁用DMA引擎
- 关闭写回缓存
2.2 主驱逐阶段(Core Eviction)
这是显存管理的核心阶段,涉及复杂的迁移决策:
关键迁移路径:
-
VRAM → 不可见显存 (首选路径)
- 需要检查不可见显存容量
- 通过DMA引擎完成数据传输
-
VRAM → GTT (次选路径)
- 当不可见显存不足时采用
- 需要考虑GTT容量限制
-
GTT → 系统内存 (最后选择)
- 当GTT空间不足时触发
- 可能影响休眠镜像大小
性能关键参数:
-
radeon.gtt_size:调整GTT空间大小 -
radeon.vram_limit:限制VRAM使用量 -
ttm.page_pool_size:控制TTM页池大小
2.3 后驱逐阶段(Post-Eviction)
驱逐完成后需要确保系统状态一致:
-
PCI设备状态管理 :
pci_disable_device(pdev); // 禁用PCI设备 -
内存一致性检查 :
- 验证所有关键BO已正确迁移
- 检查内存引用计数归零
-
错误恢复准备 :
- 设置恢复标记
- 保存必要的硬件状态
3. 容量关系与休眠成功率
3.1 关键容量参数
| 参数 | 典型值 | 影响范围 |
|---|---|---|
| VRAM容量 | 2GB-16GB | 决定可保留的显存数据量 |
| GTT大小 | 通常为VRAM的1/2 | 影响中间缓冲能力 |
| 系统内存 | 8GB-64GB | 决定最终休眠镜像大小 |
3.2 容量不足的解决方案
当遇到休眠失败时,可考虑以下调整:
内核参数调整:
# 增大GTT空间(需重启生效)
echo "options radeon gtt_size=2048" > /etc/modprobe.d/radeon.conf
# 限制VRAM使用
echo "options radeon vram_limit=1536" >> /etc/modprobe.d/radeon.conf
用户空间预防措施:
// 应用层检测示例
long vram_free = radeon_gem_info(RADEON_GEM_INFO_VRAM_FREE);
if (vram_free < MIN_REQUIRED) {
trigger_early_eviction();
}
3.3 测试案例分析
基于提供的测试代码,我们观察到:
-
VRAM耗尽行为 :
- 当VRAM使用达到75%时开始驱逐
- 每次驱逐批处理约500MB数据
-
GTT溢出处理 :
[drm:radeon_bo_evict_GTT] GTT空间不足,开始向系统内存迁移 -
休眠失败临界点 :
- 系统内存需求 = VRAM使用量 + GTT使用量
- 当超过80%系统内存时休眠可能失败
4. 唤醒流程与BO恢复
4.1 唤醒阶段的核心任务
-
硬件初始化 :
evergreen_resume(rdev); // ASIC特定恢复例程 radeon_restore_bios_scratch_regs(rdev); -
GART表恢复 :
- 第一个被pin回VRAM的BO
- 需要特殊处理DMA映射
-
显示系统重启 :
- 重新初始化显示管道
- 恢复显示模式设置
4.2 按需恢复机制
BO的恢复采用懒加载策略:
int radeon_bo_list_validate(struct radeon_device *rdev,
struct list_head *head)
{
list_for_each_entry(entry, head, tv.head) {
ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
}
}
恢复触发条件:
- 应用通过ioctl提交命令
- BO验证发现位置不匹配
- 显存访问缺页异常
4.3 性能优化建议
-
BO分配策略 :
// 优先分配不可见显存 args.initial_domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; -
唤醒加速技巧 :
- 预加载关键BO(如桌面环境)
- 启用异步恢复机制
- 调整TTM缓存策略
-
调试信息收集 :
# 查看BO状态 cat /sys/kernel/debug/dri/0/radeon_bo # 监控迁移事件 echo 1 > /sys/module/drm/parameters/trace
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)