03 - AMDGPU驱动架构概览

难度 : 🟡 进阶
预计学习时间 : 1-1.5小时
前置知识: Linux驱动基础、前两章内容


📋 概述

在深入SVM实现细节之前,我们需要理解AMDGPU驱动的整体架构。AMDGPU是一个复杂的驱动系统,包含显卡驱动(AMDGPU)和计算驱动(KFD)两大部分。SVM功能主要在KFD中实现,但与AMDGPU的其他组件紧密协作。

本章将介绍驱动的层次结构、关键组件以及SVM在其中的位置。


3.1 AMDGPU驱动整体架构

AMD GPU驱动实际上包含两个主要部分:

复制代码
┌─────────────────────────────────────────┐
│         用户空间应用                      │
│  [OpenGL] [Vulkan] [OpenCL] [HIP]       │
└─────────────────────────────────────────┘
         ↓           ↓          ↓
    ┌────────┐  ┌─────────┐  ┌─────────┐
    │Mesa/驱动│  │libdrm   │  │ROCm RT  │
    └────────┘  └─────────┘  └─────────┘
         ↓           ↓          
    ======================================
                  内核空间
    ======================================
         ↓                     ↓
    ┌──────────┐          ┌──────────┐
    │ AMDGPU   │          │   KFD    │
    │  (DRM)   │ ←──────→ │ (Compute)│
    │ 图形驱动  │          │  计算驱动  │
    └──────────┘          └──────────┘
         ↓                     ↓
    ┌────────────────────────────┐
    │        GPU 硬件             │
    │  [GFX] [Compute] [SDMA]    │
    └────────────────────────────┘
AMDGPU驱动
  • 位置 : drivers/gpu/drm/amd/amdgpu/
  • 作用 :
    • 图形渲染支持
    • 显示输出(DisplayPort, HDMI等)
    • GPU内存管理(TTM)
    • GPU电源管理
    • 基础硬件抽象
KFD驱动(Kernel Fusion Driver)
  • 位置 : drivers/gpu/drm/amd/amdkfd/
  • 作用 :
    • HSA支持(Heterogeneous System Architecture)
    • 计算队列管理
    • 进程管理
    • SVM实现 ← 我们关注的重点
    • 调试支持

目录结构

复制代码
drivers/gpu/drm/amd/
├── amdgpu/              # AMDGPU核心驱动
│   ├── amdgpu_vm.c      # 虚拟内存管理
│   ├── amdgpu_ttm.c     # TTM内存管理
│   ├── amdgpu_device.c  # 设备初始化
│   └── ...
├── amdkfd/              # KFD计算驱动 ★ SVM在这里
│   ├── kfd_module.c     # 模块初始化
│   ├── kfd_device.c     # 设备管理
│   ├── kfd_process.c    # 进程管理
│   ├── kfd_svm.c        # SVM实现 (4272行)
│   ├── kfd_svm.h        # SVM头文件
│   ├── kfd_migrate.c    # 页面迁移
│   └── ...
├── include/
│   └── kgd_kfd_interface.h  # AMDGPU与KFD接口
└── ...

3.2 KFD (Kernel Fusion Driver) 简介

KFD的历史

KFD是为HSA设计的:

  • 目标: 让CPU和GPU平等协作
  • 理念: "GPU is a first-class compute citizen"
  • 特性: 统一地址空间、用户态队列、抢占支持

KFD的核心组件

复制代码
┌───────────────────────────────────────┐
│             KFD 驱动                   │
├───────────────────────────────────────┤
│ ┌────────────┐  ┌────────────┐        │
│ │进程管理     │  │设备管理      │        │
│ │kfd_process │  │kfd_device  │        │
│ └────────────┘  └────────────┘        │
│ ┌────────────┐  ┌─────────────┐       │
│ │队列管理     │  │中断处理       │       │
│ │kfd_queue   │  │kfd_interrupt│       │
│ └────────────┘  └─────────────┘       │
│ ┌────────────┐  ┌────────────┐        │
│ │内存管理     │  │拓扑管理      │        │
│ │kfd_svm     │  │kfd_topology│        │
│ └────────────┘  └────────────┘        │
│ ┌────────────┐  ┌────────────┐        │
│ │事件管理     │  │调试支持      │        │
│ │kfd_events  │  │kfd_debug   │        │
│ └────────────┘  └────────────┘        │
└───────────────────────────────────────┘
1. 进程管理(kfd_process.c)
c 复制代码
struct kfd_process {
    struct mm_struct *mm;           // 进程的内存管理结构
    struct mutex mutex;
    uint32_t pasid;                 // Process Address Space ID
    
    struct kfd_process_device *pdds[MAX_GPU_INSTANCE];
    
    struct svm_range_list svms;     // ★ SVM范围列表
    
    // 其他成员...
};

作用

  • 每个使用KFD的进程都有一个 kfd_process 结构
  • 管理进程在所有GPU上的资源
  • 持有SVM范围列表
2. 设备管理(kfd_device.c)
c 复制代码
struct kfd_dev {
    struct amdgpu_device *adev;     // 指向AMDGPU设备
    struct kfd_device_info device_info;
    
    // 与AMDGPU交互的接口
    const struct kfd2kgd_calls *kfd2kgd;
    
    // 设备内存信息
    struct dev_pagemap pgmap;       // ★ 设备内存页面映射
    
    // 其他成员...
};

初始化流程

复制代码
GPU硬件探测
    ↓
amdgpu驱动加载
    ↓
调用 kgd2kfd_probe()  ← AMDGPU通知KFD
    ↓
创建 kfd_dev 结构
    ↓
kgd2kfd_device_init() ← 初始化KFD设备
    ↓
注册到拓扑系统
    ↓
设备就绪
3. 字符设备接口(kfd_chardev.c)

KFD通过字符设备暴露给用户空间:

bash 复制代码
/dev/kfd  # 主要接口

IOCTL命令(部分):

c 复制代码
#define AMDKFD_IOC_CREATE_QUEUE         // 创建计算队列
#define AMDKFD_IOC_DESTROY_QUEUE        // 销毁队列
#define AMDKFD_IOC_SET_MEMORY_POLICY    // 设置内存策略
#define AMDKFD_IOC_SVM                  // ★ SVM操作
// ... 更多

SVM IOCTL流程

c 复制代码
用户空间调用: ioctl(kfd_fd, AMDKFD_IOC_SVM, &args)
    ↓
kfd_ioctl() 分发
    ↓
kfd_ioctl_svm() ← kfd_chardev.c
    ↓
svm_ioctl() ← kfd_svm.c
    ↓
处理具体的SVM操作(添加范围、设置属性等)

3.3 TTM (Translation Table Maps)

什么是TTM

TTM是DRM子系统提供的GPU内存管理框架:

复制代码
┌────────────────────────────────────┐
│           TTM 框架                  │
├────────────────────────────────────┤
│ • 管理VRAM和GTT内存                  │
│ • Buffer Object (BO) 管理           │
│ • 内存驱逐和交换                     │
│ • 与系统内存交互                     │
└────────────────────────────────────┘
        ↓                  ↓
   ┌─────────┐        ┌─────────┐
   │  VRAM   │        │   GTT   │
   │(GPU显存) │        │(系统内存)│
   └─────────┘        └─────────┘

TTM的内存域(Memory Domain)

c 复制代码
// TTM定义的内存类型
#define TTM_PL_SYSTEM   0   // 系统RAM
#define TTM_PL_TT       1   // GTT (Graphics Translation Table)
#define TTM_PL_VRAM     2   // GPU显存
#define TTM_PL_PRIV     3   // 驱动私有

Buffer Object (BO)

c 复制代码
struct amdgpu_bo {
    struct ttm_buffer_object tbo;   // TTM BO基类
    
    // VRAM位置
    u64 vram_offset;
    
    // 偏好域
    u32 preferred_domains;
    
    // 允许的域
    u32 allowed_domains;
    
    // 其他成员...
};

BO的生命周期

复制代码
1. 创建BO
   amdgpu_bo_create()
       ↓
   分配TTM资源
       ↓
   
2. 放置BO(可能在VRAM或系统内存)
   amdgpu_bo_pin() / ttm_bo_validate()
       ↓
   
3. CPU访问
   amdgpu_bo_kmap() ← 建立内核映射
       ↓
   
4. GPU访问
   通过GPU页表映射
       ↓
   
5. 驱逐(内存不足时)
   ttm_bo_evict()
       ↓
   移动到系统内存
       ↓
   
6. 销毁
   amdgpu_bo_unref()

TTM与SVM的关系

SVM也使用TTM管理VRAM:

c 复制代码
// kfd_svm.c中
struct svm_range_bo {
    struct amdgpu_bo *bo;  // ← 使用TTM BO
    // ...
};

// 分配VRAM给SVM范围
int svm_range_vram_node_new(...) {
    // 创建amdgpu_bo
    ret = amdgpu_bo_create(...);
    // ...
}

关键区别

  • 传统BO:整块分配,显式管理
  • SVM:按需分配页面,自动迁移

3.4 GART表的作用

什么是GART

GART (Graphics Address Remapping Table) 是GPU的地址重映射表,允许GPU访问系统内存。

复制代码
没有GART:
GPU只能访问VRAM ✗

有GART:
GPU可以通过GART访问系统RAM ✓

GART的工作原理

复制代码
GPU视角的地址空间:
┌──────────────────────┐
│  0x0000_0000         │
│  ...                 │  ← VRAM (直接映射)
│  VRAM End            │
├──────────────────────┤
│  GART Start          │
│  ...                 │  ← GART窗口(映射系统RAM)
│  GART End            │
└──────────────────────┘

GART映射表:
GPU地址 → DMA地址(系统内存物理地址)

示例

c 复制代码
// 系统内存页面的DMA地址: 0x8000_1000
// GART映射: GPU地址 0xF000_0000 → DMA 0x8000_1000

// GPU执行:
load R1, [0xF000_0000]  // GPU地址
    ↓
GART查表
    ↓
通过PCIe访问 0x8000_1000  // 系统内存

GART在SVM中的使用

SVM使用GART进行页面迁移:

c 复制代码
// kfd_migrate.c

// 使用GART映射系统内存页面
svm_migrate_gart_map(ring, npages, dma_addr, &gart_addr, flags);

// 使用SDMA在GART地址和VRAM间复制
amdgpu_copy_buffer(ring, gart_addr, vram_addr, size, ...);

为什么需要GART

  1. SDMA只能访问GPU地址空间
  2. 系统内存不在GPU地址空间中
  3. GART将系统内存"映射"到GPU地址空间
  4. SDMA现在可以访问系统内存了

流程:

复制代码
系统内存页面
    ↓
建立GART映射 → GPU可见地址
    ↓
SDMA从GPU地址拷贝 → VRAM

3.5 SVM在驱动中的位置

SVM的模块划分

复制代码
kfd_svm.c      # SVM核心逻辑
├─ 范围管理 
│  ├─ svm_range_add()
│  ├─ svm_range_unlink()
│  └─ svm_range_split()
├─ 页面映射 
│  ├─ svm_range_map_to_gpu()
│  ├─ svm_range_unmap_from_gpu()
│  └─ svm_range_validate_and_map()
├─ 缺页处理 
│  ├─ svm_range_restore_pages()
│  └─ 页面恢复逻辑
├─ MMU Notifier
│  └─ svm_range_cpu_invalidate_pagetables()
├─ IOCTL接口
│  └─ svm_ioctl()
└─ 其他辅助功能

kfd_migrate.c      # 页面迁移
├─ RAM → VRAM迁移
├─ VRAM → RAM迁移
├─ GART映射管理
└─ SDMA复制操作

kfd_svm.h    # SVM数据结构定义

SVM与其他组件的交互

复制代码
┌──────────────────────────────┐
│            用户空间           │
│         (ROCm Runtime)       │
└──────────────────────────────┘
              ↓ IOCTL
    ========================
           内核空间
    ========================
              ↓
    ┌──────────────┐
    │  kfd_chardev │  ← IOCTL分发
    └──────────────┘
              ↓
    ┌──────────────┐
    │   kfd_svm    │  ← SVM核心
    └──────────────┘
         ↓    ↓    ↓
    ┌────┐ ┌────┐ ┌────┐
    │HMM │ │TTM │ │VM  │  ← 内核子系统
    └────┘ └────┘ └────┘
         ↓    ↓    ↓
    ┌──────────────────┐
    │   kfd_migrate    │  ← 页面迁移
    └──────────────────┘
              ↓
    ┌──────────────────┐
    │   AMDGPU驱动      │
    │  (SDMA, VM, ...) │
    └──────────────────┘
              ↓
    ┌──────────────────┐
    │    GPU硬件        │
    └──────────────────┘

关键接口

1. KFD ↔ AMDGPU接口
c 复制代码
// include/kgd_kfd_interface.h

struct kfd2kgd_calls {
    // GPU VM操作
    int (*map_memory_to_gpu)(...);
    int (*unmap_memory_from_gpu)(...);
    
    // SDMA操作
    int (*submit_ib)(...);
    
    // 其他...
};
2. SVM ↔ HMM接口
c 复制代码
// kfd_svm.c中使用HMM

// 查询CPU页表
ret = hmm_range_fault(&range);

// 迁移页面
ret = migrate_vma_setup(&migrate);
// ...
ret = migrate_vma_finalize(&migrate);
3. SVM ↔ 进程管理接口
c 复制代码
// kfd_process.c

struct kfd_process {
    struct svm_range_list svms;  // SVM范围列表
    // ...
};

// 进程初始化时
svm_range_list_init(p);

// 进程退出时
svm_range_list_fini(p);

💡 重点提示

  1. 双驱动架构:AMDGPU负责图形,KFD负责计算。SVM在KFD中实现。

  2. KFD是核心 :SVM的所有逻辑都在 drivers/gpu/drm/amd/amdkfd/ 目录下。

  3. TTM管理VRAM:SVM使用TTM的BO机制管理GPU显存。

  4. GART是桥梁:GART让GPU能够访问系统内存,是迁移的关键。

  5. 接口抽象良好:KFD通过接口与AMDGPU交互,解耦合度高。


⚠️ 常见误区

误区1:"SVM是AMDGPU驱动的功能"

  • ✅ 正确理解:SVM是KFD的功能,虽然依赖AMDGPU,但主要代码在KFD中。

误区2:"TTM和SVM是竞争关系"

  • ✅ 正确理解:SVM使用TTM管理VRAM,是合作关系。

误区3:"GART只用于传统内存访问"

  • ✅ 正确理解:SVM页面迁移也大量使用GART。

误区4:"KFD只支持AMD GPU"

  • ✅ 正确理解:KFD是AMD的实现,但HSA理念是通用的。

📝 实践练习

  1. 代码探索

    bash 复制代码
    cd drivers/gpu/drm/amd/amdkfd
    
    # 查看模块初始化
    grep -n "module_init\|module_exit" kfd_module.c
    
    # 查看KFD与AMDGPU的接口
    grep -n "kgd2kfd" kfd_device.c | head -20
    
    # 统计SVM代码量
    wc -l kfd_svm.c kfd_migrate.c
  2. 思考题

    • 为什么需要独立的KFD驱动,而不是把所有功能放在AMDGPU中?
    • GART表的大小有限制吗?如果限制,如何影响SVM?
    • TTM的驱逐机制如何与SVM协作?
  3. 系统观察

    bash 复制代码
    # 查看KFD设备(需要AMD GPU和ROCm)
    ls -l /dev/kfd
    
    # 查看GPU拓扑
    cat /sys/class/kfd/kfd/topology/nodes/*/name
    
    # 查看SVM支持(如果CONFIG_HSA_AMD_SVM=y)
    dmesg | grep -i svm

📚 本章小结

  • 双驱动架构:AMDGPU(图形)+ KFD(计算)
  • KFD组件:进程管理、设备管理、队列管理、SVM等
  • TTM:GPU内存管理框架,SVM使用TTM管理VRAM
  • GART:地址重映射表,让GPU访问系统内存

理解这些架构层次,有助于在后续章节深入SVM的具体实现。


📖 扩展阅读

➡️ 下一步

完成了基础篇的学习,我们已经建立了必要的知识背景。接下来进入数据结构篇,我们将详细剖析SVM的核心数据结构。


🔗 导航

相关推荐
DeeplyMind2 天前
ROCm rocr-libhsakmt分析系列4: HsaMemFlags分析
rocm·rocr·libhsakmt·hsamemflags
DeeplyMind3 天前
附录A:AMDGPU SVM 属性类型
kfd·amdgpu svm
DeeplyMind3 天前
04 - SVM核心数据结构详解
svm·amdgpu·kfd
DeeplyMind5 天前
02 - SVM相关的Linux内核基础
hmm·rocm·kfd·共享虚拟内存·amdgpu svm
DeeplyMind6 天前
01 - 什么是SVM
svm·amdgpu·rocm·kfd
DeeplyMind10 天前
AMD ROCm-SVM技术的实现与应用深度分析目录
svm·rocm·kfd
DeeplyMind12 天前
引文:当SVM转角遇上Copy-on-Write (COW)
svm·copy-on-write·cow·mmu notifier
DeeplyMind1 个月前
AMD KFD的BO设计分析系列8-7:TLB管理与刷新
amdgpu·tlb·kfd
越努力越幸运~1 个月前
AMD AI MAX +395迷你主机 架构1151安装 vllm部署大模型操作记录
ai·vllm·rocm·ai max+395