4. GPU IOMMU/MMU 配置:iommus 属性、dma-ranges、IOMMU 与 SMMU 在设备树中的描述
在 DRM 与 GPU 驱动移植中,IOMMU(Input-Output Memory Management Unit)与 SMMU(System MMU)是连接 GPU 与系统内存的关键硬件单元。设备树中必须正确描述这些内存管理单元,否则 GPU 无法进行 DMA 操作,导致驱动初始化失败或内存访问异常。本章节深入解析 iommus 属性、dma-ranges 属性以及 IOMMU/SMMU 在设备树中的完整描述方法。
4.1 IOMMU/SMMU 在 GPU 驱动中的角色
GPU 作为高性能 DMA 设备,需要直接访问系统内存中的帧缓冲、纹理数据、命令缓冲区等。IOMMU/SMMU 提供以下关键能力:
- 地址翻译:将 GPU 发出的设备虚拟地址(DVA)翻译为系统物理地址(PA)。
- 内存保护:防止 GPU 访问未授权的内存区域,提高系统安全性。
- 连续映射:将物理上不连续的内存页映射为 GPU 视角的连续地址空间。
- 大页支持:减少 TLB 缺失,提升 GPU 内存访问性能。
iommus 属性用于将 GPU 设备绑定到特定的 SMMU 实例。
4.2 iommus 属性详解
iommus 属性是设备树中用于将设备连接到 IOMMU 的标准属性。其语法格式如下:
iommus = <phandle stream-id> [, <phandle stream-id> ...];
参数说明:
| 参数 | 描述 | 示例值 |
|---|---|---|
phandle |
指向 IOMMU/SMMU 节点的句柄 | &smmu |
stream-id |
设备在 IOMMU 中的唯一标识符(Stream ID) | 0x100 |
以下是一个典型的 GPU 节点 iommus 配置示例:
gpu: gpu@f0000000 {
compatible = "arm,mali-g72";
reg = <0x0 0xf0000000 0x0 0x10000>;
interrupts = <0 42 4>;
iommus = <&smmu 0x100>;
#iommu-cells = <1>;
};
iommus = <&smmu 0x100 &smmu 0x101>。
4.3 dma-ranges 属性解析
dma-ranges 属性用于描述设备能够进行 DMA 操作的内存地址范围。它定义了从设备地址空间到 CPU 地址空间的映射关系。语法格式如下:
dma-ranges = <child-bus-addr parent-bus-addr length> [, ...];
参数说明:
| 参数 | 描述 | 示例值 |
|---|---|---|
child-bus-addr |
设备总线地址(GPU 视角的地址) | 0x0 |
parent-bus-addr |
父总线地址(CPU 物理地址) | 0x80000000 |
length |
映射的内存范围大小 | 0x80000000 |
实际配置示例:
gpu: gpu@f0000000 {
compatible = "arm,mali-g72";
reg = <0x0 0xf0000000 0x0 0x10000>;
interrupts = <0 42 4>;
iommus = <&smmu 0x100>;
dma-ranges = <0x0 0x80000000 0x80000000>;
};
dma-ranges 与 iommus 同时使用时,IOMMU 会覆盖 dma-ranges 的地址映射。如果 IOMMU 配置正确,dma-ranges 可以省略;但在没有 IOMMU 的场景下,dma-ranges 是必需的。
4.4 SMMU 节点在设备树中的描述
SMMU 节点本身也需要在设备树中完整描述。以下是一个标准的 ARM SMMU v3 节点示例:
smmu: iommu@f0100000 {
compatible = "arm,smmu-v3";
reg = <0x0 0xf0100000 0x0 0x20000>;
interrupts = <0 48 4>,
<0 49 4>,
<0 50 4>;
interrupt-names = "eventq", "gerror", "priq";
#iommu-cells = <1>;
dma-coherent;
};
SMMU 节点关键属性说明:
| 属性 | 描述 | 是否必需 |
|---|---|---|
compatible |
SMMU 兼容性字符串,如 "arm,smmu-v3" |
是 |
reg |
SMMU 寄存器基地址和大小 | 是 |
interrupts |
SMMU 中断号列表 | 是 |
#iommu-cells |
指定 iommus 属性中 Stream ID 的 cell 数量 |
是 |
dma-coherent |
指示 SMMU 与 CPU 之间缓存一致性 | 否 |
4.5 GPU 与 SMMU 连接关系图
下图展示了 GPU 节点、SMMU 节点与系统内存之间的 IOMMU 连接关系:
4.6 IOMMU 配置流程
在 GPU 驱动初始化过程中,IOMMU 的配置遵循以下步骤:
- 解析设备树:驱动读取 GPU 节点的
iommus属性,获取 SMMU 句柄和 Stream ID。 - 获取 SMMU 实例:通过
of_parse_phandle()获取 SMMU 设备节点。 - 创建 IOMMU 映射:调用
iommu_domain_alloc()分配 IOMMU 域。 - 绑定设备:使用
iommu_attach_device()将 GPU 设备绑定到 IOMMU 域。 - 配置地址映射:通过
iommu_map()建立 GPU 虚拟地址到物理地址的映射。 - 启用 DMA:完成映射后,GPU 即可通过 IOMMU 进行 DMA 操作。
of_parse_phandle(dev, "iommus", 0) → 获取 SMMU 节点iommu_domain_alloc(bus) → 分配 IOMMU 域iommu_attach_device(domain, dev) → 绑定设备iommu_map(domain, iova, phys, size, prot) → 建立映射
4.7 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| GPU DMA 超时 | Stream ID 配置错误 | 检查 iommus 属性中的 Stream ID 是否与硬件一致 |
| IOMMU 页错误 | 地址映射未建立或权限不足 | 使用 iommu_debug 内核参数查看详细错误 |
| 驱动 probe 失败 | SMMU 节点未正确描述 | 检查 SMMU 节点的 compatible 和 reg 属性 |
| 内存访问越界 | dma-ranges 范围过小 |
确认 dma-ranges 覆盖 GPU 所需的所有内存区域 |
4.8 多 GPU 场景下的 IOMMU 配置
在异构计算或多 GPU 系统中,每个 GPU 可能需要独立的 IOMMU 配置。以下是一个双 GPU 配置示例:
gpu0: gpu@f0000000 {
compatible = "arm,mali-g72";
reg = <0x0 0xf0000000 0x0 0x10000>;
iommus = <&smmu 0x100>;
};
gpu1: gpu@f0010000 {
compatible = "arm,mali-g72";
reg = <0x0 0xf0010000 0x0 0x10000>;
iommus = <&smmu 0x200>;
};
4.9 本章小结
IOMMU/SMMU 配置是 GPU 驱动移植中的关键环节。设备树中的 iommus 属性将 GPU 设备绑定到 SMMU 实例,dma-ranges 属性定义 DMA 地址范围,而 SMMU 节点本身需要完整描述其寄存器、中断和兼容性。正确配置这些属性是 GPU 驱动正常工作的前提。