vfio: retry creating sPAPR DMA window
authorTakeshi Yoshimura <tyos@jp.ibm.com>
Fri, 7 Jun 2019 02:28:29 +0000 (11:28 +0900)
committerThomas Monjalon <thomas@monjalon.net>
Sun, 7 Jul 2019 21:20:23 +0000 (23:20 +0200)
sPAPR allows only page_shift from VFIO_IOMMU_SPAPR_TCE_GET_INFO ioctl.
However, Linux 4.17 or before returns incorrect page_shift for Power9.
I added the code for retrying creation of sPAPR DMA window.

Signed-off-by: Takeshi Yoshimura <tyos@jp.ibm.com>
Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
lib/librte_eal/linux/eal/eal_vfio.c

index fdc884f..7053ebe 100644 (file)
@@ -1445,9 +1445,29 @@ vfio_spapr_create_new_dma_window(int vfio_container_fd,
        /* create new DMA window */
        ret = ioctl(vfio_container_fd, VFIO_IOMMU_SPAPR_TCE_CREATE, create);
        if (ret) {
-               RTE_LOG(ERR, EAL, "  cannot create new DMA window, "
-                               "error %i (%s)\n", errno, strerror(errno));
-               return -1;
+               /* try possible page_shift and levels for workaround */
+               uint32_t levels;
+
+               for (levels = 1; levels <= info.ddw.levels; levels++) {
+                       uint32_t pgsizes = info.ddw.pgsizes;
+
+                       while (pgsizes != 0) {
+                               create->page_shift = 31 - __builtin_clz(pgsizes);
+                               create->levels = levels;
+                               ret = ioctl(vfio_container_fd,
+                                       VFIO_IOMMU_SPAPR_TCE_CREATE, create);
+                               if (!ret)
+                                       break;
+                               pgsizes &= ~(1 << create->page_shift);
+                       }
+                       if (!ret)
+                               break;
+               }
+               if (ret) {
+                       RTE_LOG(ERR, EAL, "  cannot create new DMA window, "
+                                       "error %i (%s)\n", errno, strerror(errno));
+                       return -1;
+               }
        }
 
        if (create->start_addr != 0) {