• iommu 和 dma 虚拟地址


    iova支持

    所谓iova可以理解为io的地址,或者说是DMA的地址。在17.11中很多之前的phys_addr关键字都被替换为了iova关键字了。因为在之前dpdk不感知iommu,设置DMA都是用物理地址,但是在借助iommu时就可以使用虚拟地址进行DMA了。在rte_eal_init中还有如下调用:

             /* autodetect the iova mapping mode (default is iova_pa) */

             rte_eal_get_configuration()->iova_mode = rte_bus_get_iommu_class();

    通过调用对应bus的get_iommu_class函数,来获取iova的模式。

     rte_bus_get_iommu_class

    点击(此处)折叠或打开

    1. enum rte_iova_mode
    2. rte_bus_get_iommu_class(void)
    3. {
    4.          int mode = RTE_IOVA_DC;
    5.          struct rte_bus *bus;
    6.  
    7.          TAILQ_FOREACH(bus, &rte_bus_list, next) {
    8.  
    9.                    if (bus->get_iommu_class)
    10.                             mode |= bus->get_iommu_class();
    11.          }
    12.  
    13.          if (mode != RTE_IOVA_VA) {
    14.                    /* Use default IOVA mode */
    15.                    mode = RTE_IOVA_PA;
    16.          }
    17.          return mode;
    18. }

        iova有两种模式,一种是RTE_IOVA_VA,一种是RTE_IOVA_PA,RTE_IOVA_VA表示DMA操作可以使用虚拟地址表示目的地址,而RTE_IOVA_PA则表示DMA必须要用物理地址作为目的地址。

    我们以pci的get_iommu_class为例,其对应实现为

    l<span "="">  rte_pci_get_iommu_class

    点击(此处)折叠或打开

    1. /*
    2.  * Get iommu class of PCI devices on the bus.
    3.  */
    4. enum rte_iova_mode
    5. rte_pci_get_iommu_class(void)
    6. {
    7.          bool is_bound;
    8.          bool is_vfio_noiommu_enabled = true;
    9.          bool has_iova_va;
    10.          bool is_bound_uio;
    11.          bool iommu_no_va;
    12.     /* 设备是否已经bonding相应驱动 */
    13.          is_bound = pci_one_device_is_bound();
    14.          if (!is_bound)
    15.                    return RTE_IOVA_DC;
    16.  
    17.          has_iova_va = pci_one_device_has_iova_va(); /*是否有设备是否支持iova_va */
    18.          is_bound_uio = pci_one_device_bound_uio(); /*是否有设备绑定了uio*/
    19.          iommu_no_va = !pci_devices_iommu_support_va(); /*iommu是否支持使用虚拟地址作为iova*/
    20.          if (has_iova_va && !is_bound_uio && !is_vfio_noiommu_enabled &&
    21.                             !iommu_no_va)
    22.                    return RTE_IOVA_VA;
    23.  
    24.          if (has_iova_va) {
    25.                    RTE_LOG(WARNING, EAL, "Some devices want iova as va but pa will be used because.. ");
    26.                    if (is_vfio_noiommu_enabled)
    27.                             RTE_LOG(WARNING, EAL, "vfio-noiommu mode configured ");
    28.                    if (is_bound_uio)
    29.                             RTE_LOG(WARNING, EAL, "few device bound to UIO ");
    30.                    if (iommu_no_va)
    31.                             RTE_LOG(WARNING, EAL, "IOMMU does not support IOVA as VA ");
    32.          }
    33.  
    34.          return RTE_IOVA_PA;
    35. }

    决定pci设备最终的iova mode的条件有三个。首先是has_iova_va,这个通过pci_one_device_has_iova_va来判断。

    pci_one_device_has_iova_va

    点击(此处)折叠或打开

    1. static inline int
    2. pci_one_device_has_iova_va(void)
    3. {
    4.          struct rte_pci_device *dev = NULL;
    5.          struct rte_pci_driver *drv = NULL;
    6.  
    7.          FOREACH_DRIVER_ON_PCIBUS(drv) {
    8.                    if (drv && drv->drv_flags & RTE_PCI_DRV_IOVA_AS_VA) {
    9.                             FOREACH_DEVICE_ON_PCIBUS(dev) {
    10.                                      if (dev->kdrv == RTE_KDRV_VFIO &&
    11.                                          rte_pci_match(drv, dev))
    12.                                                return 1;
    13.                             }
    14.                    }
    15.          }
    16.          return 0;
    17. }

    从这个函数的逻辑可以看出当设备对应的pmd驱动支持RTE_PCI_DRV_IOVA_AS_VA,且设备当前绑定了vfio驱动,则认为这个设备支持RTE_IOVA_VA。

    第二个条件为is_bound_uio,通过pci_one_device_bound_uio来获取,其实就是判断是否有pci设备绑定了uio驱动,我们指定uio驱动是不支持iommu的,一旦有绑定uio的设备就不能使用RTE_IOVA_VA

    第三个条件为iommu_no_va,这个条件通过pci_devices_iommu_support_va来获取,也就是多去pci设备目录下的iommu特性,判断iommu是否可以支持用虚拟地址作为DMA地址。如下所示:

    $cat /sys/bus/pci/devices/0000:01:00.0/iommu/intel-iommu/cap

    8d2078c106f0466

        所以判断dpdk最终是否能够使用虚拟地址作为DMA地址除了设备绑定vfio和pmd支持之外,还需要有iommu对应特性的支持以及不能有设备绑定uio

    另外注意在rte_eal_init中还有如下判断逻辑,即如果当前主机加载了kni模块就不能在使用RTE_IOVA_VA模式了,因为kni需要依赖RTE_IOVA_PA。

    点击(此处)折叠或打开

    1. /* Workaround for KNI which requires physical address to work */
    2.          if (rte_eal_get_configuration()->iova_mode == RTE_IOVA_VA &&
    3.                             rte_eal_check_module("rte_kni") == 1) {
    4.                    rte_eal_get_configuration()->iova_mode = RTE_IOVA_PA;
    5.                    RTE_LOG(WARNING, EAL,
    6.                             "Some devices want IOVA as VA but PA will be used because.. "
    7.                             "KNI module inserted ");
    8.          }
  • 相关阅读:
    MongoDB
    Django配置实现数据库读写分离
    基于scrapy-redis的分布式爬虫
    增量式爬虫
    Pyhton网络爬虫之CrawlSpider
    Scrapy 之如何发送post请求
    Scrapy 之settings配置
    Scrapy 实现爬取多页数据 + 多层url数据爬取
    Scrapy 框架入门简介
    redis操作总结
  • 原文地址:https://www.cnblogs.com/dream397/p/13834175.html
Copyright © 2020-2023  润新知