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\n");
  28.                    if (is_bound_uio)
  29.                             RTE_LOG(WARNING, EAL, "few device bound to UIO\n");
  30.                    if (iommu_no_va)
  31.                             RTE_LOG(WARNING, EAL, "IOMMU does not support IOVA as VA\n");
  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\n");
  8.          }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM