前面介绍了SMMU设备的生成和识别,但IO设备是如何与SMMU设备关联的呢?一个SMMU设备下面可能有多个IO设备,但每个IO设备只在一个SMMU设备下。
根据驱动设备模型,当IO设备与IO驱动匹配时,会触发IO驱动的probe函数,在其实在调用驱动probe()之前,会调用与IOMMU相关的函数。其过程如下:
整个匹配的probe过程中执行的内容较多,这里仅介绍红色部分,即我们关心的DMA相关的设置和设备驱动的probe()(对于IO设备来説,它为IO设备驱动的probe()函数,注意并不是SMMU设备驱动的probe())。
其中dev->bus->dma_configure()则是本节的重点,它负责将IO设备与SMMU设备关联起来,可见该操作在IO设备的probe()函数之前完成。
对于platform device,dma_configure的回调函数为platform_dma_configure();对于PCIE设备,dma_configure的回调函数为pci_dma_configure()。但两者最终都调用都一样。
暂只介绍ACPI方式的DMA配置acpi_dma_confiugre()。
这里主要作如下三个操作:
- 函数acpi_arch_dma_setup()返回设备支持DMA大小,对于ARM64上来説,默认为48bit大小;
- 函数acpi_iommu_configure_id()获取设备以及对应的SMMU相关的配置如iommu_ops,并probe设备建立dma_domain;后面重点讲解函数iommu_probe_device();
- 函数arch_setup_dma_ops()主要对dma_domain分配并初始化IOVA domain;
其中函数iommu_probe_device()是关联IO设备和SMMU设备的关键函数,它为IO设备分配iommu_device,同时为IO设备分配iommu_group,将IO设备对应在iommu_device加入到iommu_group中。
在介绍该函数前简单介绍下重要的结构体iommu_ops和几个概念。
1. 结构体iommu_ops
结构体iommu_ops定义了底层硬件对应的回调函数,对于SMMU或INTEL IOMMU都会基于硬件定义自己的iommu_ops。结构体iommu_ops各成员函数定义和描述如下所示,这里仅作简单介绍:
成员函数 | 作用 |
capable | 检查能力 |
domain_alloc | 分配iommu domain |
domain_free | 释放iommu domain |
attach_dev | 将设备连接到iommu domain |
detach_dev | 取消设备到iommu domain的连接 |
map | 映射物理连续的内存区域到iommu domain |
map_pages | 映射一组物理连续的内存区域到iommu domain |
unmap | 取消物理连续的内存区域到iommu domain的映射 |
unmap_pages | 取消一组物理连续的内存区域到iommu domain的映射 |
flush_iotlb_all | 同步刷新某个domain的所有硬件TLB |
iotlb_sync_map | SMMUV3没有定义 |
iotlb_sync | 刷新某个domain的某个范围的TLB |
iova_to_phys | 将iova转化为物理地址 |
probe_device | 将设备放入到iommu驱动处理 |
release_device | 将设备从iommu驱动处理中释放 |
Probe_finalize | 在设备添加到iommu group并关联到group domain后的最后一步 |
Device_group | 对某个设备找到或分配iommu group |
Enable_nesting | 使能2个stage |
Set_pgtable_quirks | 设置页表相关的workaround |
Get_resv_regions | 获取一个设备保留的区域 |
Put_resv_regions | 释放一个设备保留的区域 |
Apply_resv_regions | SMMUV3没有定义 |
Of_xlate | 增加master ID到iommu group转换 |
Is_attach_deferred | ARM没有使用 |
dev_has/enable/disable_feat | 检查/使能/禁用iommu某些特性 |
Dev_feat_enabled | 判断是否使能特性 |
Aux_attach/detach_dev | Aux-domain的链接或取消链接到设备 |
Aux_get_pasid | 对给定的aux-domain获取pasid |
sva_bind | 将进程地址空间绑定到设备 |
Sva_unbind | 取消绑定进程地址空间到设备 |
Sva_get_pasid | 获取共SVA相关的PASID |
Page_response | 处理页请求回复 |
Cache_invalidate | 无效化转换缓存 |
Sva_bind_gpasid | 将guest pasid与mm绑定 |
sva_unbind_gpasid | 将guest pasid与mm取消绑定 |
Def_domain_type | 设备默认的domain类型(SMMUV3没有定义) |
Pgsize_bitmap | 所有支持的页大小的bitmap |
2. IOMMU相关的结构体关系
Iommu_device对应一个IO设备(或PCIE概念中的Function);
Iommu_group为共享相同IO地址空间的设备的集合(可能一个或多个);
Iommu_domain的范围和iommu_group一样,但它定义的是group范围内对应的操作的集合;