03 - DRM子系统与AMDGPU架构

难度 : 🟡 进阶级
预计学习时间 : 60分钟
前置知识 : 02-GPU显存管理基础


📋 概述

理解DRM和AMDGPU架构是深入学习Buddy分配器的关键。本章介绍:

  • 🏗️ DRM子系统: Linux图形驱动的统一框架
  • 🎯 AMDGPU架构: AMD GPU驱动的设计
  • 🔗 集成关系: Buddy如何融入整个架构
  • 📊 数据流向: 从应用到硬件的完整路径

3.1 DRM核心架构

DRM是什么?

DRM 是Linux内核的图形子系统:

复制代码
历史演进:
  早期 (1990s): 每个厂商独立驱动 → 混乱
         ↓
  DRM诞生 (2000s): 统一内核接口 → 标准化
         ↓
  现代 (2010s+): GEM/TTM/KMS → 功能完善

DRM提供:
✓ 统一的设备管理 (/dev/dri/*)
✓ 内存管理框架 (GEM/TTM)
✓ 显示模式设置 (KMS)
✓ GPU调度器
✓ 统一的用户态接口 (ioctl)

DRM子系统分层

复制代码
┌─────────────────────────────────────────────┐
│          用户空间                            │
│  ┌──────────┐  ┌───────┐  ┌──────────┐      │
│  │ X Server │  │Wayland│  │   Mesa   │      │
│  └────┬─────┘  └───┬───┘  └────┬─────┘      │
│       └────────────┼───────────┘            │
│                    │ libdrm                 │
└────────────────────┼────────────────────────┘
                     │ ioctl
┌────────────────────┼────────────────────────┐
│   DRM Core (内核)   │                        │
│  ┌─────────────────▼──────────────┐         │
│  │  DRM Device Management         │         │
│  │  - 设备注册                     │         │
│  │  - IOCTL分发                    │         │
│  └──────────────┬─────────────────┘         │
│                 │                           │
│  ┌──────────────▼──────────────┐            │
│  │  DRM Memory Management      │            │
│  │  ┌──────┐      ┌────────┐   │            │
│  │  │ GEM  │      │  TTM   │   │            │
│  │  └──────┘      └────────┘   │            │
│  └─────────────────────────────┘            │
│                 │                           │
│  ┌──────────────▼──────────────┐            │
│  │  Display (KMS)              │            │
│  │  - Mode setting             │            │
│  │  - CRTC/Encoder/Connector   │            │
│  └─────────────────────────────┘            │
└────────────────┬────────────────────────────┘
                 │
┌────────────────▼────────────────────────────┐
│   厂商驱动 (amdgpu/i915/nouveau...)          │
│  ┌──────────────────────────────┐           │
│  │  Hardware Specific Logic     │           │
│  │  - 寄存器操作                  │           │
│  │  - 中断处理                   │           │
│  │  - 固件加载                   │           │
│  └──────────────────────────────┘           │
└─────────────────────────────────────────────┘

GEM vs TTM

两种内存管理框架:

c 复制代码
// GEM - Intel等使用
// 特点: 简单,基于BO (Buffer Object)

struct drm_gem_object {
    struct drm_device *dev;
    struct file *filp;
    u32 handle;         // 用户态句柄
    size_t size;        // 大小
    // ...
};

// TTM  - AMD/Nouveau使用
// 特点: 复杂,支持多种内存域和迁移

struct ttm_buffer_object {
    struct drm_gem_object base;  // 继承GEM
    
    struct ttm_resource *resource;   // 实际资源
    struct ttm_placement placement;  // 放置策略
    
    // 支持VRAM ↔ GTT ↔ System 迁移
};

对比:
┌──────────┬─────────────┬──────────────┐
│ 特性      │    GEM      │     TTM      │
├──────────┼─────────────┼──────────────┤
│ 复杂度    │ 低          │ 高            │
│ 内存域    │ 单一         │ 多域+迁移     │
│ 用户      │ Intel等     │ AMD/Nouveau  │
│ 灵活性    │ 基础         │ 强大         │
└──────────┴─────────────┴──────────────┘

3.2 DRM内存管理框架

TTM Resource Manager接口

c 复制代码
// include/drm/ttm/ttm_resource.h

struct ttm_resource_manager_func {
    // 分配资源
    int (*alloc)(struct ttm_resource_manager *man,
                 struct ttm_buffer_object *bo,
                 const struct ttm_place *place,
                 struct ttm_resource **res);
    
    // 释放资源
    void (*free)(struct ttm_resource_manager *man,
                 struct ttm_resource *res);
    
    // 查询接口
    void (*debug)(struct ttm_resource_manager *man,
                  struct drm_printer *printer);
};

// 资源管理器实例
struct ttm_resource_manager {
    const struct ttm_resource_manager_func *func;
    u64 size;          // 总大小
    u64 usage;         // 已用大小
    void *priv;        // 私有数据 (例如: amdgpu_vram_mgr)
    // ...
};

TTM BO生命周期

c 复制代码
// 创建和销毁流程

// 1. 创建BO
int ttm_bo_init_reserved(struct ttm_device *bdev,
                         struct ttm_buffer_object *bo,
                         size_t size,
                         struct ttm_placement *placement)
{
    bo->base.size = size;
    bo->bdev = bdev;
    
    // 分配内存资源
    ttm_bo_mem_space(bo, placement, &mem);
    bo->resource = mem;
    
    return 0;
}

// 2. 分配内存
static int ttm_bo_mem_space(struct ttm_buffer_object *bo,
                            struct ttm_placement *placement,
                            struct ttm_resource **mem)
{
    // 遍历placement中的首选域
    for (i = 0; i < placement->num_placement; i++) {
        place = &placement->placement[i];
        
        // 获取对应的资源管理器
        man = ttm_manager_type(bdev, place->mem_type);
        
        // 调用管理器的分配函数
        ret = man->func->alloc(man, bo, place, mem);
        
        if (!ret)
            return 0;  // 分配成功
    }
    
    return -ENOMEM;  // 所有域都分配失败
}

// 3. 使用BO (应用程序操作)

// 4. 销毁BO
void ttm_bo_put(struct ttm_buffer_object *bo)
{
    kref_put(&bo->kref, ttm_bo_release);
}

static void ttm_bo_release(struct kref *kref)
{
    struct ttm_buffer_object *bo;
    bo = container_of(kref, struct ttm_buffer_object, kref);
    
    // 释放资源
    if (bo->resource) {
        man = ttm_manager_type(bdev, bo->resource->mem_type);
        man->func->free(man, bo->resource);  // 调用VRAM Manager
    }
    
    kfree(bo);
}

内存域和放置策略

c 复制代码
// 定义BO的内存域偏好

static int amdgpu_bo_create(struct amdgpu_device *adev,
                            struct amdgpu_bo_param *bp,
                            struct amdgpu_bo **bo_ptr)
{
    struct ttm_placement placement;
    struct ttm_place places[3];
    int num_places = 0;
    
    // 场景1: 优先VRAM,GTT作为备选
    if (bp->preferred_domain & AMDGPU_GEM_DOMAIN_VRAM) {
        places[num_places].mem_type = TTM_PL_VRAM;
        places[num_places].flags = 0;
        num_places++;
        
        if (bp->allowed_domain & AMDGPU_GEM_DOMAIN_GTT) {
            places[num_places].mem_type = TTM_PL_TT;  // GTT
            num_places++;
        }
    }
    
    placement.num_placement = num_places;
    placement.placement = places;
    
    // TTM会按顺序尝试每个domain
    ttm_bo_init_reserved(adev->mman.bdev, &bo->tbo,
                        bp->size, &placement);
    
    return 0;
}

// 结果:
// 1. 先尝试从VRAM分配
// 2. VRAM不足 → 尝试从GTT分配
// 3. GTT也不足 → 返回失败

3.3 AMDGPU驱动架构概览

AMDGPU模块结构

复制代码
drivers/gpu/drm/amd/amdgpu/
├── amdgpu.h                    # 主头文件
├── amdgpu_drv.c                # 驱动入口,模块注册
├── amdgpu_device.c             # 设备初始化
├── amdgpu_kms.c                # KMS接口实现
├── amdgpu_gem.c                # GEM接口 (BO创建等)
│
├── amdgpu_ttm.c                # TTM集成层
├── amdgpu_vram_mgr.c           # VRAM管理器 ← 使用Buddy
├── amdgpu_gtt_mgr.c            # GTT管理器
│
├── amdgpu_vm.c                 # GPU虚拟内存
├── amdgpu_cs.c                 # Command Submission
├── amdgpu_fence.c              # 同步原语
│
├── amdgpu_gfx.c                # Graphics Engine
├── amdgpu_sdma.c               # SDMA Engine
├── amdgpu_display.c            # Display子系统
│
└── ... (更多子模块)

核心数据结构:
struct amdgpu_device           # 设备实例
    ├── struct amdgpu_mman     # 内存管理器
    │       └── struct amdgpu_vram_mgr  # VRAM管理器
    │               └── struct drm_buddy mm  # Buddy实例
    ├── struct amdgpu_vm       # GPU VM
    └── ...

驱动初始化流程

c 复制代码
// amdgpu_drv.c - 模块初始化

static int __init amdgpu_init(void)
{
    // 注册PCI驱动
    pci_register_driver(&amdgpu_kms_pci_driver);
    
    return 0;
}

// PCI设备探测时调用
static int amdgpu_pci_probe(struct pci_dev *pdev,
                           const struct pci_device_id *ent)
{
    // 创建DRM设备
    drm_dev_alloc(&amdgpu_kms_driver, &pdev->dev);
    
    // 初始化AMDGPU设备
    amdgpu_device_init(adev, pdev);
    
    // 注册DRM设备
    drm_dev_register(ddev, ent->driver_data);
    
    return 0;
}

// amdgpu_device.c - 设备初始化
int amdgpu_device_init(struct amdgpu_device *adev,
                       struct pci_dev *pdev)
{
    // 1. 早期初始化
    amdgpu_device_early_init(adev);
    
    // 2. 内存管理器初始化 ← 关键步骤
    amdgpu_ttm_init(adev);
    
    // 3. GPU初始化
    amdgpu_device_ip_init(adev);
    
    // 4. 其他子系统...
    
    return 0;
}

// amdgpu_ttm.c - TTM初始化
int amdgpu_ttm_init(struct amdgpu_device *adev)
{
    struct amdgpu_mman *mman = &adev->mman;
    
    // 初始化TTM设备
    ttm_device_init(&mman->bdev, &amdgpu_bo_driver,
                   adev->dev, ...);
    
    // 注册VRAM管理器 ← Buddy在这里创建
    amdgpu_vram_mgr_init(adev);
    
    // 注册GTT管理器
    amdgpu_gtt_mgr_init(adev);
    
    return 0;
}

3.4 AMDGPU VRAM管理器

amdgpu_vram_mgr 结构

c 复制代码
// drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c

struct amdgpu_vram_mgr {
    struct ttm_resource_manager manager;  // 继承TTM管理器
    
    struct drm_buddy mm;        // ← Buddy分配器实例
    
    atomic64_t usage;           // 当前使用量
    atomic64_t vis_usage;       // Visible区域使用量
    
    u64 default_page_size;      // 默认页大小
    
    struct list_head reservations_pending;  // 待处理的预留
    struct list_head reserved_pages;        // 已预留的页面
    
    struct mutex lock;          // 保护并发访问
};

// VRAM块资源
struct amdgpu_vram_mgr_resource {
    struct ttm_resource base;   // TTM资源基类
    
    struct list_head blocks;    // Buddy分配的块列表
    unsigned long flags;        // 标志 (CONTIGUOUS, CLEAR等)
};

VRAM管理器初始化

c 复制代码
// 初始化VRAM管理器
int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
{
    struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
    struct ttm_resource_manager *man = &mgr->manager;
    
    // 获取VRAM大小
    u64 vram_size = adev->gmc.real_vram_size;
    u64 visible_size = adev->gmc.visible_vram_size;
    
    // 初始化Buddy分配器 ← 关键调用
    drm_buddy_init(&mgr->mm, vram_size, PAGE_SIZE);
    
    // 注册为TTM资源管理器
    man->func = &amdgpu_vram_mgr_func;
    ttm_resource_manager_init(man, &adev->mman.bdev, vram_size);
    
    // 设置为VRAM类型
    ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, man);
    
    DRM_INFO("VRAM Manager initialized: %llu MB total, %llu MB visible\n",
             vram_size >> 20, visible_size >> 20);
    
    return 0;
}

// 示例输出:
// [drm] VRAM Manager initialized: 8192 MB total, 256 MB visible

VRAM分配实现

c 复制代码
// TTM调用的分配接口
static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                              struct ttm_buffer_object *bo,
                              const struct ttm_place *place,
                              struct ttm_resource **res)
{
    struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
    struct amdgpu_vram_mgr_resource *vres;
    u64 size = bo->base.size;
    u64 min_block_size = PAGE_SIZE;
    unsigned long flags = 0;
    
    // 创建资源对象
    vres = kzalloc(sizeof(*vres), GFP_KERNEL);
    INIT_LIST_HEAD(&vres->blocks);
    
    // 处理对齐要求
    if (place->lpfn) {
        min_block_size = place->lpfn << PAGE_SHIFT;
    }
    
    // 处理标志
    if (place->flags & TTM_PL_FLAG_CONTIGUOUS)
        flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION;
    
    // 调用Buddy分配 ← 核心调用
    mutex_lock(&mgr->lock);
    
    drm_buddy_alloc_blocks(&mgr->mm,
                          0,              // start
                          mgr->mm.size,   // end
                          size,           // size
                          min_block_size, // alignment
                          &vres->blocks,  // output
                          flags);
    
    mutex_unlock(&mgr->lock);
    
    // 更新统计
    atomic64_add(size, &mgr->usage);
    
    *res = &vres->base;
    return 0;
}

// 释放接口
static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
                               struct ttm_resource *res)
{
    struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
    struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
    
    mutex_lock(&mgr->lock);
    
    // 释放所有Buddy块
    drm_buddy_free_list(&mgr->mm, &vres->blocks);
    
    mutex_unlock(&mgr->lock);
    
    // 更新统计
    atomic64_sub(res->size, &mgr->usage);
    
    kfree(vres);
}

// 资源管理器函数表
static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
    .alloc = amdgpu_vram_mgr_new,
    .free = amdgpu_vram_mgr_del,
    .debug = amdgpu_vram_mgr_debug,
};

3.5 Buddy分配器在整体架构中的位置

完整的调用链

复制代码
用户空间应用 (Vulkan游戏)
    ↓ vkAllocateMemory()
Mesa Vulkan驱动 (libvulkan_radeon.so)
    ↓ radv_device_memory_create()
libdrm (libdrm_amdgpu.so)
    ↓ amdgpu_bo_alloc()
    ↓ ioctl(DRM_IOCTL_AMDGPU_GEM_CREATE)
════════════════════════════════════════
内核空间 (AMDGPU驱动)
    ↓
amdgpu_gem_create_ioctl()         [amdgpu_gem.c]
    ↓ 验证参数,处理flags
amdgpu_bo_create()                [amdgpu_object.c]
    ↓ 设置placement (VRAM优先)
ttm_bo_init_reserved()            [ttm_bo.c]
    ↓ TTM核心逻辑
ttm_bo_mem_space()                [ttm_bo.c]
    ↓ 遍历placement,选择内存域
amdgpu_vram_mgr_new()             [amdgpu_vram_mgr.c]
    ↓ VRAM管理器
drm_buddy_alloc_blocks()          [drm_buddy.c]
    ↓ Buddy算法核心
    ├─ alloc_from_freelist()
    ├─ split_block()
    └─ 返回分配的块
════════════════════════════════════════
物理VRAM硬件

数据结构关系图

复制代码
┌─────────────────────────────────────┐
│  struct amdgpu_device (设备实例)     │
│  ┌───────────────────────────────┐  │
│  │  struct amdgpu_mman           │  │
│  │  ┌─────────────────────────┐  │  │
│  │  │ struct ttm_device bdev  │  │  │
│  │  │  - VRAM manager         │  │  │
│  │  │  - GTT manager          │  │  │
│  │  └───────┬─────────────────┘  │  │
│  │          │                    │  │
│  │  ┌───────▼───────────────────┐│  │
│  │  │ struct amdgpu_vram_mgr    ││  │
│  │  │  ┌─────────────────────┐  ││  │
│  │  │  │ struct drm_buddy mm │  ││  │
│  │  │  │  - chunk_size       │  ││  │
│  │  │  │  - max_order        │  ││  │
│  │  │  │  - free_list[]      │  ││  │
│  │  │  │  - roots[]          │  ││  │
│  │  │  └─────────────────────┘  ││  │
│  │  │                           ││  │
│  │  │  atomic64_t usage         ││  │
│  │  │  struct mutex lock        ││  │
│  │  └───────────────────────────┘│  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘

Buddy操作的对象

c 复制代码
// Buddy管理的是VRAM的物理偏移

// 例如: 8GB VRAM,物理地址范围 0x0 - 0x200000000

// 分配16MB在偏移0x10000000处:
struct drm_buddy_block *block = ...;
block->offset = 0x10000000;       // 256MB偏移
block->size = 16 * 1024 * 1024;   // 16MB大小

// 转换为物理地址 (GPU可访问):
phys_addr = adev->gmc.vram_start + block->offset;
// = 0xE0000000 (例如PCIe BAR地址) + 0x10000000
// = 0xF0000000

// GPU访问这块内存:
gpu_addr = phys_addr;  // GPU物理地址
// 或者通过页表映射到GPU虚拟地址

// CPU访问 (仅Visible VRAM):
if (block->offset < adev->gmc.visible_vram_size) {
    void *cpu_ptr = adev->mman.aper_base_kaddr + block->offset;
    // CPU可以直接读写
}

并发控制

c 复制代码
// VRAM Manager使用互斥锁保护Buddy操作

// 分配路径
static int amdgpu_vram_mgr_new(...)
{
    mutex_lock(&mgr->lock);      // 加锁
    
    drm_buddy_alloc_blocks(...); // 操作Buddy
    
    mutex_unlock(&mgr->lock);    // 解锁
    
    return 0;
}

// 释放路径
static void amdgpu_vram_mgr_del(...)
{
    mutex_lock(&mgr->lock);      // 加锁
    
    drm_buddy_free_list(...);    // 操作Buddy
    
    mutex_unlock(&mgr->lock);    // 解锁
}

// 原因:
// - Buddy数据结构不是线程安全的
// - 多个CPU核心可能同时分配/释放
// - 需要互斥锁保证操作的原子性

💡 重点提示

  1. DRM是框架: 提供统一接口,具体实现由各厂商驱动完成。

  2. TTM是抽象层: 隔离了内存域细节,支持多种资源管理器。

  3. VRAM Manager是策略层: 决定如何分配(对齐、范围、统计等)。

  4. Buddy是执行层: 纯粹的分配算法,不关心上层策略。

  5. 层次分明: 每层职责清晰,修改Buddy不影响上层接口。

  6. 互斥保护: 所有Buddy操作都在锁保护下,确保线程安全。


⚠️ 常见陷阱

陷阱1: "可以直接调用drm_buddy API"

  • ✅ 正确: 应该通过TTM接口,让VRAM Manager协调。

陷阱2: "Buddy管理虚拟地址"

  • ✅ 正确: Buddy管理物理偏移(offset),虚拟地址由GPU VM管理。

陷阱3: "修改Buddy就能优化性能"

  • ✅ 正确: 性能瓶颈可能在上层(TTM、BO管理),需要整体分析。

陷阱4: "VRAM分配失败就是Buddy的问题"

  • ✅ 正确: 可能是碎片、可能是总量不足、可能是范围限制。

📝 实践练习

  1. 追踪完整调用链

    bash 复制代码
    # 使用ftrace追踪一次BO创建
    echo 'function_graph' > /sys/kernel/debug/tracing/current_tracer
    echo 'amdgpu_gem_create_ioctl' > /sys/kernel/debug/tracing/set_ftrace_filter
    echo 1 > /sys/kernel/debug/tracing/tracing_on
    
    # 运行一个简单的GPU程序
    # ...
    
    cat /sys/kernel/debug/tracing/trace
    # 观察函数调用层次
  2. 查看VRAM使用统计

    bash 复制代码
    # 查看VRAM Manager状态
    cat /sys/kernel/debug/dri/0/amdgpu_vram_mm
    
    # 查看所有BO信息
    cat /sys/kernel/debug/dri/0/amdgpu_gem_info
    
    # 分析输出,理解Buddy块的分布
  3. 理解placement策略

    c 复制代码
    // 设计不同场景的placement
    
    // 场景1: 纹理(可以在VRAM或GTT)
    places[0] = {.mem_type = TTM_PL_VRAM};
    places[1] = {.mem_type = TTM_PL_TT};
    
    // 场景2: Framebuffer(必须Visible VRAM)
    places[0] = {
        .mem_type = TTM_PL_VRAM,
        .fpfn = 0,
        .lpfn = visible_size >> PAGE_SHIFT
    };
    
    // 场景3: Compute buffer(只要VRAM)
    places[0] = {.mem_type = TTM_PL_VRAM};

本章小结

  • DRM架构: 统一的Linux图形驱动框架,包含内存管理、显示、调度等
  • TTM框架: 内存管理抽象层,支持多域、迁移、资源管理器
  • AMDGPU结构: 模块化设计,VRAM Manager使用Buddy作为底层分配器
  • 调用链: 从用户态ioctl到内核Buddy分配,层层传递
  • Buddy定位: 最底层的物理内存块管理,职责单一清晰

理解了整体架构后,我们已经具备了深入学习Buddy数据结构和算法的基础。


📚 参考资料

➡️ 下一步

掌握了DRM和AMDGPU架构后,下一章将深入Buddy的核心数据结构,理解代码组织和设计思想。

👉 [04-核心数据结构详解]评审中...


相关推荐
DeeplyMind2 小时前
04 - 核心数据结构详解
drm·drm_buddy·vram
DeeplyMind3 个月前
Linux DRM 内存管理子系统的概念关系理解:gem、ttm、drm_buddy
drm·tm·drm_buddy
DeeplyMind3 个月前
第7章:DRM内核调试技术:7.1 DRM DebugFS的使用
linux·驱动开发·drm·debugfs·drm debugfs
DeeplyMind4 个月前
linux drm子系统技术分析目录表
linux·驱动开发·drm
Micro麦可乐4 个月前
前端真的能防录屏?EME(加密媒体扩展) DRM 反录屏原理 + 实战代码
前端·媒体·eme·drm·前端防盗录
JasonSJX5 个月前
海海软件成为微软 PlayReady DRM 官方合作伙伴
microsoft·drm·视频加密·playready·数字版权保护
DeeplyMind5 个月前
linux drm子系统专栏介绍
linux·驱动开发·ai·drm·amdgpu·kfd
DeeplyMind7 个月前
AMD KFD的BO设计分析系列3-4:Linux DRM GEM mmap 与 drm_vma_offset_node 机制详解
linux·drm·opengl驱动·drm_gem_object
林政硕(Cohen0415)1 年前
Linux驱动开发进阶(七)- DRM驱动程序设计
linux·驱动开发·drm