前文:AMD rocr-libhsakmt分析系列7-1: doorbell机制概览中,描述了AMD的doorbell的机制。本文重点描述KFD中的相关实现。
1. doorbell 的硬件原理
doorbell(门铃)是 AMD GPU 架构中用于CPU与 GPU 硬件之间高效通信的一种机制。
它本质上是一块映射到用户/内核空间的物理寄存器区间(GPU/GPGPU设备上一个存储空间),进程或驱动通过写入特定的 doorbell 索引(index),即可向 GPU 某个硬件引擎(如调度器、DMA、Compute 队列等)发出“有新任务”或“状态变更”的通知。
doorbell 区域通常位于 PCIe BAR2(Base Address Register 2)空间,大小数 KB 到数 MB 不等。每个 doorbell 索引对应 32 位(dword)或 64 位(qword)寄存器。doorbell BAR 通过 mmap映射到用户/内核空间,支持进程隔离和权限控制。
2. doorbell 在 AMDGPU 驱动中的实现
2.1 doorbell 相关数据结构
在 AMDGPU 驱动中,doorbell 相关结构体为:
struct amdgpu_doorbell {
resource_size_t base; // Doorbell BAR 基地址
resource_size_t size; // Doorbell BAR 大小
u32 num_kernel_doorbells; // 内核可用 doorbell 数量
struct amdgpu_bo *kernel_doorbells; // 内核 doorbell BO
u32 *cpu_addr; // Doorbell 映射到 CPU 的虚拟地址
};
-
base和size由 PCIe BAR2 获取。 -
num_kernel_doorbells表示内核预留的 doorbell 数量。 -
kernel_doorbells是内核分配的 doorbell BO(Buffer Object)。 -
cpu_addr是 doorbell aperture 的虚拟地址,供内核/用户空间直接访问。
2.2 doorbell 的初始化流程
2.2.1 doorbell BAR 的初始化
这个过程在驱动初始化时执行,确定好doorbell的基地址和空间大小。
nt amdgpu_doorbell_init(struct amdgpu_device *adev)
{
if (adev->asic_type < CHIP_BONAIRE) {
adev->doorbell.base = 0;
adev->doorbell.size = 0;
adev->doorbell.num_kernel_doorbells = 0;
return 0;
}
if (pci_resource_flags(adev->pdev, 2) & IORESOURCE_UNSET)
return -EINVAL;
amdgpu_asic_init_doorbell_index(adev);
adev->doorbell.base = pci_resource_start(adev->pdev, 2);
adev->doorbell.size = pci_resource_len(adev->pdev, 2);
adev->doorbell.num_kernel_doorbells =
min_t(u32, adev->doorbell.size / sizeof(u32),
adev->doorbell_index.max_assignment + 1);
if (adev->doorbell.num_kernel_doorbells == 0)
return -EINVAL;
if (adev->asic_type >= CHIP_VEGA10)
adev->doorbell.num_kernel_doorbells += 0x400;
return 0;
}
-
通过 PCIe BAR2 获取 doorbell 的物理地址和大小。
-
计算可用 doorbell 数量,部分为内核预留,部分可分配给用户进程。
-
Vega10 及以后架构会额外预留一页 doorbell 空间。
2.2.2 内核doorbell BO 的分配
在驱动初始化各memory的管理器后,就会调用下面的函数初始化内核用的doorbell。所以这个初始化的时机是比较早的。在不支持user doorbell的需求中,会使用内核doorbell。在AMD的内核代码中,注释是这样的:amdgpu_doorbell_create_kernel_doorbells - Create kernel doorbells for graphics。看起来是专给图形驱动用的,KFD走user doorbell。
//调用链
amdgpu_bo_init
amdgpu_ttm_init
amdgpu_doorbell_create_kernel_doorbells
int amdgpu_doorbell_create_kernel_doorbells(struct amdgpu_device *adev)
{
int size = ALIGN(adev->doorbell.num_kernel_doorbells * sizeof(u32), PAGE_SIZE);
adev->mes.db_start_dw_offset = size / sizeof(u32);
size += PAGE_SIZE;
int r = amdgpu_bo_create_kernel(adev,
size,
PAGE_SIZE,
AMDGPU_GEM_DOMAIN_DOORBELL,
&adev->doorbell.kernel_doorbells,
NULL,
(void **)&adev->doorbell.cpu_addr);
if (r) {
DRM_ERROR("Failed to allocate kernel doorbells, err=%d\n", r);
return r;
}
adev->doorbell.num_kernel_doorbells = size / sizeof(u32);
return 0;
}
-
分配一个doorbell bo 映射到内核虚拟地址空间。
-
cpu_addr指向 doorbell aperture 的起始地址,供内核直接读写。
2.2.3 内核doorbell BO的释放
void amdgpu_doorbell_fini(struct amdgpu_device *adev)
{
amdgpu_bo_free_kernel(&adev->doorbell.kernel_doorbells,
NULL,
(void **)&adev->doorbell.cpu_addr);
}
-
释放 doorbell BO,解除映射。
2.3 Doorbell 的读写操作
2.3.1 内核空间读写
u32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index)
{
if (index < adev->doorbell.num_kernel_doorbells)
return readl(adev->doorbell.cpu_addr + index);
DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index);
return 0;
}
void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v)
{
if (index < adev->doorbell.num_kernel_doorbells)
writel(v, adev->doorbell.cpu_addr + index);
else
DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
}
-
通过
readl/writel直接访问 doorbell aperture,实现低延迟通知。 -
64 位 doorbell 用
atomic64_read/atomic64_set实现。
2.4 doorbell 索引的分配与管理
doorbell 索引由驱动统一分配,分为内核保留和用户进程分配两部分。每个进程/队列分配独立的 doorbell 索引,避免冲突。doorbell 分配表(如 adev->doorbell_index)记录所有已分配的索引。进程退出或队列销毁时,驱动回收对应的 doorbell 索引,供后续分配复用。
3. Doorbell 的典型调用路径
3.1 用户空间提交任务的流程
-
用户空间将任务描述符写入共享内存(如 command buffer)。
-
用户空间写入自己的 doorbell 索引(通过 mmap 的 doorbell aperture)。
-
GPU 硬件检测到 doorbell 变化,读取任务描述符并执行。
3.2 内核空间 doorbell 操作
-
内核驱动在调度、队列管理、测试等场景下,也会直接写 doorbell,通知 GPU 执行特定操作。
3.3 Doorbell 索引的分配与回收
-
进程创建时,驱动分配 doorbell 索引,并通过 ioctl 或 mmap 传递给用户空间。
-
进程退出时,驱动回收 doorbell 索引,清理资源。
接下来分析libhskmt里doorbell的应用,详见:AMD rocr-libhsakmt分析系列7-2:doorbell的实现。
786

被折叠的 条评论
为什么被折叠?



