IOMMU(二)-从配置说起

2021-04-28 10:19:09 浏览数 (1)

惠伟:DMA和IOMMU(一)-简单介绍​zhuanlan.zhihu.com

做过DPDK/SPDK开发或者用kvm做过pci passthrough的一定知道以下的配置:

BIOS中enable vt-d,内核参数配置intel_iommu=on iommu=pt

好多人对这些配置很疑惑,不知道这些配置的是做什么的,配或者不配对性能有什么影响。

包括我自己曾经也一知半解,今天整理一下,争取让大家柳暗花明。

enable vt-d

意思很明确,BIOS收集IOMMU硬件相关的信息以及它和PCI设备连接关系的信息,通过ACPI的表上报给操作系统

intel_iommu=on

用intel_iommu驱动来驱动IOMMU硬件单元,IOMMU硬件有intel/amd/arm的等,我们一般用intel的硬件,当然用intel的iommu驱动了。

iommu=pt

我们先看内核中关于这个配置的注释

代码语言:javascript复制
/*
 * This variable becomes 1 if iommu=pt is passed on the kernel command line.
 * If this variable is 1, IOMMU implementations do no DMA translation for
 * devices and allow every device to access to whole physical memory. This is
 * useful if a user wants to use an IOMMU only for KVM device assignment to
 * guests and not for driver dma translation.
 */

光看注释理解还不太深刻,下面分析一下代码加深理解。

早期kvm pci passthrough的实现,qemu用到的参数是-device pci-assign,host=01:00.0,kvm最终调用了iommu的代码domain_pfn_mapping。

代码语言:javascript复制
kvm_iommu_map_pages
  └─iommu_map
      └─intel_iommu_map(domain->ops->map)
          └─domain_pfn_mapping

kvm也用了vfio-pci,qemu参数-device vfio-pci,host=b1:00.0,最终也调用了iommu的代码domain_pfn_mapping。

代码语言:javascript复制
vfio_iommu_type1_ioctl
  └─vfio_dma_do_map
      └─vfio_pin_map_dma
          └─vfio_iommu_map
              └─iommu_map
                  └─intel_iommu_map(domain->ops->map)
                     └─domain_pfn_mapping

我们再看内核i40e的代码,它也调用到了domain_pfn_mapping。

代码语言:javascript复制
i40e_alloc_mapped_page
  └─dma_map_page
      └─intel_map_page
          └─__intel_map_single
              ├─if(iommu_no_mapping) return paddr;
              ├─intel_alloc_iova
              └─domain_pfn_mapping

发现kvm/vfio/i40e都调用到了函数domain_pfn_mapping,相比于kvm和vfio,i40e多了一个if判断,条件是函数iommu_no_mapping的返回值。

代码语言:javascript复制
/* Check if the dev needs to go through non-identity map and unmap process.*/
static int iommu_no_mapping(struct device *dev)
{
	int found;

	if (iommu_dummy(dev))
		return 1;

	if (!iommu_identity_mapping)
		return 0;

	found = identity_mapping(dev);
	if (found) {
		if (iommu_should_identity_map(dev, 0))
			return 1;
		else {
			/*
			 * 32 bit DMA is removed from si_domain and fall back
			 * to non-identity mapping.
			 */
			dmar_remove_one_dev_info(si_domain, dev);
			pr_info("32bit %s uses non-identity mappingn",
				dev_name(dev));
			return 0;
		}
	} else {
		/*
		 * In case of a detached 64 bit DMA device from vm, the device
		 * is put into si_domain for identity mapping.
		 */
		if (iommu_should_identity_map(dev, 0)) {
			int ret;
			ret = domain_add_dev_info(si_domain, dev);
			if (!ret) {
				pr_info("64bit %s uses identity mappingn",
					dev_name(dev));
				return 1;
			}
		}
	}

	return 0;
}

再回头看iommu初始化的代码

代码语言:javascript复制
static int __init init_dmars(void)
{
	if (iommu_pass_through)
		iommu_identity_mapping |= IDENTMAP_ALL;
	if (iommu_identity_mapping) {
		ret = si_domain_init(hw_pass_through);
		if (ret)
			goto free_iommu;
	}

	if (iommu_identity_mapping) {
		ret = iommu_prepare_static_identity_mapping(hw_pass_through);
		if (ret) {
			pr_crit("Failed to setup IOMMU pass-throughn");
			goto free_iommu;
		}
	}
}

总结起来就是

代码语言:javascript复制
配置了iommu=pt就identity mapping
if hw_pass_through==0
   hardware identity mapping
else
   software identity mapping

说明配置了iommu=pt上面的函数iommu_no_mapping返回1,那么i40e驱动就直接return paddr,并不会真正调用到domain_pfn_mapping,直接用了物理地址少了一次映射性能当然会高一些。

总结

iommu=pt并不会影响kvm/dpdk/spdk的性能,这三者本质上都是用户态驱动,iommu=pt只会影响内核驱动,能让内核驱动设备性能更高。

补充

kvm一定要用intel_iommu=on,DPDK/SPDK如果绑定vfio-pci那也一定要求intel_iommu=on,如果绑定uio/igb_uio那么就不需要intel_iommu=on,推荐都用vfio-pci,后面kvm中的pci-assign,DPDK/SPDK用到的igb_uio都得淘汰。

还有一个内核参数是nointremap,iommu实现了dma remapping和intr remaping,kvm二者都要用,但DPDK/SPDK用轮询模式,可以不用int remapping功能,那nointremap就派上用场了。

0 人点赞