iommu_dma_alloc_iova 已经成功获取到了虚拟地址,iommu_map_sg 将把虚拟地址和物理散列表中的物理地址进行映射。 iommu_map_sg 在4.19 以后的内核这个接口已经删除了
size_t iommu_map_sg(struct iommu_domain *domain,
unsigned long iova, struct scatterlist *sg,
unsigned int nents, int prot)
{
size_t mapped;
mapped = domain->ops->map_sg(domain, iova, sg, nents, prot);
trace_map_sg(domain, iova, mapped, prot);
return mapped;
}
map_sg 调用的是arm_smmu_ops 中的arm_smmu_map_sg 其中又调用了 smmu_domain->pgtbl_ops。 smmu_domain 的初始化是在arm_smmu_master_alloc_smes 函数一步步调用完成的,参考文章https://blog.csdn.net/qq_28637193/article/details/103551684
arm_smmu_master_alloc_smes->iommu_group_get_for_dev->iommu_group_add_device->__iommu_attach_device->(domain->ops->attach_dev)->arm_smmu_attach_dev->arm_smmu_init_domain_context->
alloc_io_pgtable_ops->io_pgtable_init_table
io_pgtable_init_table 选择了不同的api 版本,以io_pgtable_arm_64_lpae_s2_init_fns 为例子分析
io_pgtable_arm_64_lpae_s2_init_fns->arm_64_lpae_alloc_pgtable_s2->arm_lpae_alloc_pgtable-> arm_lpae_map_sg
static struct arm_lpae_io_pgtable *
arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
{
unsigned long va_bits, pgd_bits;
struct arm_lpae_io_pgtable *data;
arm_lpae_restrict_pgsizes(cfg);
if (!(cfg->pgsize_bitmap & (SZ_4K | SZ_16K | SZ_64K)))
return NULL;
if (cfg->ias > ARM_LPAE_MAX_ADDR_BITS)
return NULL;
if (cfg->oas > ARM_LPAE_MAX_ADDR_BITS)
return NULL;
if (!selftest_running && cfg->iommu_dev->dma_pfn_offset) {
dev_err(cfg->iommu_dev, "Cannot accommodate DMA offset for IOMMU page tables\n");
return NULL;
}
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return NULL;
data->pg_shift = __ffs(cfg->pgsize_bitmap);
data->bits_per_level = data->pg_shift - ilog2(sizeof(arm_lpae_iopte));
va_bits = cfg->ias - data->pg_shift;
data->levels = DIV_ROUND_UP(va_bits, data->bits_per_level);
/* Calculate the actual size of our pgd (without concatenation) */
pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1));
data->pgd_bits = pgd_bits;
data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte)));
data->iop.ops = (struct io_pgtable_ops) {
.map = arm_lpae_map,
.map_sg = arm_lpae_map_sg,
.unmap = arm_lpae_unmap,
.iova_to_phys = arm_lpae_iova_to_phys,
.is_iova_coherent = arm_lpae_is_iova_coherent,
.iova_to_pte = arm_lpae_iova_get_pte,
};
return data;
}
在往下是pte 是初始化相关,与arm smmu 体系结构相关。