vfio: Pass in starting IOVA to vfio_pin/unpin_pages API
authorNicolin Chen <nicolinc@nvidia.com>
Sat, 23 Jul 2022 02:02:51 +0000 (19:02 -0700)
committerAlex Williamson <alex.williamson@redhat.com>
Mon, 25 Jul 2022 19:41:22 +0000 (13:41 -0600)
The vfio_pin/unpin_pages() so far accepted arrays of PFNs of user IOVA.
Among all three callers, there was only one caller possibly passing in
a non-contiguous PFN list, which is now ensured to have contiguous PFN
inputs too.

Pass in the starting address with "iova" alone to simplify things, so
callers no longer need to maintain a PFN list or to pin/unpin one page
at a time. This also allows VFIO to use more efficient implementations
of pin/unpin_pages.

For now, also update vfio_iommu_type1 to fit this new parameter too,
while keeping its input intact (being user_iova) since we don't want
to spend too much effort swapping its parameters and local variables
at that level.

Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Kirti Wankhede <kwankhede@nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Acked-by: Eric Farman <farman@linux.ibm.com>
Tested-by: Terrence Xu <terrence.xu@intel.com>
Tested-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Link: https://lore.kernel.org/r/20220723020256.30081-6-nicolinc@nvidia.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Documentation/driver-api/vfio-mediated-device.rst
drivers/gpu/drm/i915/gvt/kvmgt.c
drivers/s390/cio/vfio_ccw_cp.c
drivers/s390/crypto/vfio_ap_ops.c
drivers/vfio/vfio.c
drivers/vfio/vfio.h
drivers/vfio/vfio_iommu_type1.c
include/linux/vfio.h

index b0fdf76b339a4e08d45265e687a73182472e7b01..ea32a0f13ddbfe471180051376574243e0e5e92d 100644 (file)
@@ -262,10 +262,10 @@ Translation APIs for Mediated Devices
 The following APIs are provided for translating user pfn to host pfn in a VFIO
 driver::
 
-       int vfio_pin_pages(struct vfio_device *device, unsigned long *user_pfn,
+       int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova,
                                  int npage, int prot, unsigned long *phys_pfn);
 
-       void vfio_unpin_pages(struct vfio_device *device, unsigned long *user_pfn,
+       void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova,
                                    int npage);
 
 These functions call back into the back-end IOMMU module by using the pin_pages
index 2fee5695515a43c6ecd61f18c3675eba59b5aa6c..8be75c282611e36e8a0283a3d76b611794ff565e 100644 (file)
@@ -231,14 +231,8 @@ static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt)
 static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
                unsigned long size)
 {
-       int total_pages = DIV_ROUND_UP(size, PAGE_SIZE);
-       int npage;
-
-       for (npage = 0; npage < total_pages; npage++) {
-               unsigned long cur_gfn = gfn + npage;
-
-               vfio_unpin_pages(&vgpu->vfio_device, &cur_gfn, 1);
-       }
+       vfio_unpin_pages(&vgpu->vfio_device, gfn << PAGE_SHIFT,
+                        DIV_ROUND_UP(size, PAGE_SIZE));
 }
 
 /* Pin a normal or compound guest page for dma. */
@@ -255,14 +249,14 @@ static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
         * on stack to hold pfns.
         */
        for (npage = 0; npage < total_pages; npage++) {
-               unsigned long cur_gfn = gfn + npage;
+               dma_addr_t cur_iova = (gfn + npage) << PAGE_SHIFT;
                unsigned long pfn;
 
-               ret = vfio_pin_pages(&vgpu->vfio_device, &cur_gfn, 1,
+               ret = vfio_pin_pages(&vgpu->vfio_device, cur_iova, 1,
                                     IOMMU_READ | IOMMU_WRITE, &pfn);
                if (ret != 1) {
-                       gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx, ret %d\n",
-                                    cur_gfn, ret);
+                       gvt_vgpu_err("vfio_pin_pages failed for iova %pad, ret %d\n",
+                                    &cur_iova, ret);
                        goto err;
                }
 
index 3b94863ad24eabdcd7052f35aed9c3ea2a558071..a739262f988dcfbe776d54525d2f2cd15309fdb7 100644 (file)
@@ -114,7 +114,7 @@ static void pfn_array_unpin(struct pfn_array *pa,
                        continue;
                }
 
-               vfio_unpin_pages(vdev, first, npage);
+               vfio_unpin_pages(vdev, *first << PAGE_SHIFT, npage);
                unpinned += npage;
                npage = 1;
        }
@@ -146,7 +146,7 @@ static int pfn_array_pin(struct pfn_array *pa, struct vfio_device *vdev)
                        continue;
                }
 
-               ret = vfio_pin_pages(vdev, first, npage,
+               ret = vfio_pin_pages(vdev, *first << PAGE_SHIFT, npage,
                                     IOMMU_READ | IOMMU_WRITE,
                                     &pa->pa_pfn[pinned]);
                if (ret < 0) {
index 5781059d3ed2b811166ec179c25fcb5d8c75ede9..70f484668ca0fc912c090a19d3f8eda35b04875e 100644 (file)
@@ -124,7 +124,7 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
                q->saved_isc = VFIO_AP_ISC_INVALID;
        }
        if (q->saved_pfn && !WARN_ON(!q->matrix_mdev)) {
-               vfio_unpin_pages(&q->matrix_mdev->vdev, &q->saved_pfn, 1);
+               vfio_unpin_pages(&q->matrix_mdev->vdev, q->saved_pfn << PAGE_SHIFT, 1);
                q->saved_pfn = 0;
        }
 }
@@ -258,7 +258,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
                return status;
        }
 
-       ret = vfio_pin_pages(&q->matrix_mdev->vdev, &g_pfn, 1,
+       ret = vfio_pin_pages(&q->matrix_mdev->vdev, g_pfn << PAGE_SHIFT, 1,
                             IOMMU_READ | IOMMU_WRITE, &h_pfn);
        switch (ret) {
        case 1:
@@ -301,7 +301,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
                break;
        case AP_RESPONSE_OTHERWISE_CHANGED:
                /* We could not modify IRQ setings: clear new configuration */
-               vfio_unpin_pages(&q->matrix_mdev->vdev, &g_pfn, 1);
+               vfio_unpin_pages(&q->matrix_mdev->vdev, g_pfn << PAGE_SHIFT, 1);
                kvm_s390_gisc_unregister(kvm, isc);
                break;
        default:
@@ -1232,9 +1232,8 @@ static void vfio_ap_mdev_dma_unmap(struct vfio_device *vdev, u64 iova,
 {
        struct ap_matrix_mdev *matrix_mdev =
                container_of(vdev, struct ap_matrix_mdev, vdev);
-       unsigned long g_pfn = iova >> PAGE_SHIFT;
 
-       vfio_unpin_pages(&matrix_mdev->vdev, &g_pfn, 1);
+       vfio_unpin_pages(&matrix_mdev->vdev, iova, 1);
 }
 
 /**
index 92b10aafae28b89188cca45f48938f59bffb90c8..ffd1a492eea98542a22412c2a2e1e07712e298db 100644 (file)
@@ -1934,17 +1934,17 @@ int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs,
 EXPORT_SYMBOL(vfio_set_irqs_validate_and_prepare);
 
 /*
- * Pin a set of guest PFNs and return their associated host PFNs for local
+ * Pin contiguous user pages and return their associated host pages for local
  * domain only.
  * @device [in]  : device
- * @user_pfn [in]: array of user/guest PFNs to be pinned.
- * @npage [in]   : count of elements in user_pfn array.  This count should not
- *                be greater VFIO_PIN_PAGES_MAX_ENTRIES.
+ * @iova [in]    : starting IOVA of user pages to be pinned.
+ * @npage [in]   : count of pages to be pinned.  This count should not
+ *                be greater than VFIO_PIN_PAGES_MAX_ENTRIES.
  * @prot [in]    : protection flags
  * @phys_pfn[out]: array of host PFNs
  * Return error or number of pages pinned.
  */
-int vfio_pin_pages(struct vfio_device *device, unsigned long *user_pfn,
+int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova,
                   int npage, int prot, unsigned long *phys_pfn)
 {
        struct vfio_container *container;
@@ -1952,8 +1952,7 @@ int vfio_pin_pages(struct vfio_device *device, unsigned long *user_pfn,
        struct vfio_iommu_driver *driver;
        int ret;
 
-       if (!user_pfn || !phys_pfn || !npage ||
-           !vfio_assert_device_open(device))
+       if (!phys_pfn || !npage || !vfio_assert_device_open(device))
                return -EINVAL;
 
        if (npage > VFIO_PIN_PAGES_MAX_ENTRIES)
@@ -1967,7 +1966,7 @@ int vfio_pin_pages(struct vfio_device *device, unsigned long *user_pfn,
        driver = container->iommu_driver;
        if (likely(driver && driver->ops->pin_pages))
                ret = driver->ops->pin_pages(container->iommu_data,
-                                            group->iommu_group, user_pfn,
+                                            group->iommu_group, iova,
                                             npage, prot, phys_pfn);
        else
                ret = -ENOTTY;
@@ -1977,15 +1976,13 @@ int vfio_pin_pages(struct vfio_device *device, unsigned long *user_pfn,
 EXPORT_SYMBOL(vfio_pin_pages);
 
 /*
- * Unpin set of host PFNs for local domain only.
+ * Unpin contiguous host pages for local domain only.
  * @device [in]  : device
- * @user_pfn [in]: array of user/guest PFNs to be unpinned. Number of user/guest
- *                PFNs should not be greater than VFIO_PIN_PAGES_MAX_ENTRIES.
- * @npage [in]   : count of elements in user_pfn array.  This count should not
+ * @iova [in]    : starting address of user pages to be unpinned.
+ * @npage [in]   : count of pages to be unpinned.  This count should not
  *                 be greater than VFIO_PIN_PAGES_MAX_ENTRIES.
  */
-void vfio_unpin_pages(struct vfio_device *device, unsigned long *user_pfn,
-                     int npage)
+void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova, int npage)
 {
        struct vfio_container *container;
        struct vfio_iommu_driver *driver;
@@ -2000,7 +1997,7 @@ void vfio_unpin_pages(struct vfio_device *device, unsigned long *user_pfn,
        container = device->group->container;
        driver = container->iommu_driver;
 
-       driver->ops->unpin_pages(container->iommu_data, user_pfn, npage);
+       driver->ops->unpin_pages(container->iommu_data, iova, npage);
 }
 EXPORT_SYMBOL(vfio_unpin_pages);
 
index 6a8424b407c7edc7b011f5aabfbdfea6b79ead98..e9767e13f00fe80ea62e0d2eebf8821dffda6ff5 100644 (file)
@@ -50,11 +50,11 @@ struct vfio_iommu_driver_ops {
                                        struct iommu_group *group);
        int             (*pin_pages)(void *iommu_data,
                                     struct iommu_group *group,
-                                    unsigned long *user_pfn,
+                                    dma_addr_t user_iova,
                                     int npage, int prot,
                                     unsigned long *phys_pfn);
        void            (*unpin_pages)(void *iommu_data,
-                                      unsigned long *user_pfn, int npage);
+                                      dma_addr_t user_iova, int npage);
        void            (*register_device)(void *iommu_data,
                                           struct vfio_device *vdev);
        void            (*unregister_device)(void *iommu_data,
index e49fbe9968efe8e65d84caf54c9f01fa5a8ef574..e629e059118c47db1c0aa343002c9f12cde1adf9 100644 (file)
@@ -829,7 +829,7 @@ static int vfio_unpin_page_external(struct vfio_dma *dma, dma_addr_t iova,
 
 static int vfio_iommu_type1_pin_pages(void *iommu_data,
                                      struct iommu_group *iommu_group,
-                                     unsigned long *user_pfn,
+                                     dma_addr_t user_iova,
                                      int npage, int prot,
                                      unsigned long *phys_pfn)
 {
@@ -841,7 +841,7 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data,
        bool do_accounting;
        dma_addr_t iova;
 
-       if (!iommu || !user_pfn || !phys_pfn)
+       if (!iommu || !phys_pfn)
                return -EINVAL;
 
        /* Supported for v2 version only */
@@ -857,7 +857,7 @@ static int vfio_iommu_type1_pin_pages(void *iommu_data,
 again:
        if (iommu->vaddr_invalid_count) {
                for (i = 0; i < npage; i++) {
-                       iova = user_pfn[i] << PAGE_SHIFT;
+                       iova = user_iova + PAGE_SIZE * i;
                        ret = vfio_find_dma_valid(iommu, iova, PAGE_SIZE, &dma);
                        if (ret < 0)
                                goto pin_done;
@@ -882,7 +882,7 @@ again:
        for (i = 0; i < npage; i++) {
                struct vfio_pfn *vpfn;
 
-               iova = user_pfn[i] << PAGE_SHIFT;
+               iova = user_iova + PAGE_SIZE * i;
                dma = vfio_find_dma(iommu, iova, PAGE_SIZE);
                if (!dma) {
                        ret = -EINVAL;
@@ -939,7 +939,7 @@ pin_unwind:
        for (j = 0; j < i; j++) {
                dma_addr_t iova;
 
-               iova = user_pfn[j] << PAGE_SHIFT;
+               iova = user_iova + PAGE_SIZE * j;
                dma = vfio_find_dma(iommu, iova, PAGE_SIZE);
                vfio_unpin_page_external(dma, iova, do_accounting);
                phys_pfn[j] = 0;
@@ -950,7 +950,7 @@ pin_done:
 }
 
 static void vfio_iommu_type1_unpin_pages(void *iommu_data,
-                                        unsigned long *user_pfn, int npage)
+                                        dma_addr_t user_iova, int npage)
 {
        struct vfio_iommu *iommu = iommu_data;
        bool do_accounting;
@@ -964,10 +964,9 @@ static void vfio_iommu_type1_unpin_pages(void *iommu_data,
 
        do_accounting = list_empty(&iommu->domain_list);
        for (i = 0; i < npage; i++) {
+               dma_addr_t iova = user_iova + PAGE_SIZE * i;
                struct vfio_dma *dma;
-               dma_addr_t iova;
 
-               iova = user_pfn[i] << PAGE_SHIFT;
                dma = vfio_find_dma(iommu, iova, PAGE_SIZE);
                if (!dma)
                        break;
index 9f7d74c24925af1fc984b5eb2da57936523a0b9e..9e3b6abcf890673f1320249d1771377ec0db8044 100644 (file)
@@ -161,10 +161,9 @@ bool vfio_file_has_dev(struct file *file, struct vfio_device *device);
 
 #define VFIO_PIN_PAGES_MAX_ENTRIES     (PAGE_SIZE/sizeof(unsigned long))
 
-int vfio_pin_pages(struct vfio_device *device, unsigned long *user_pfn,
+int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova,
                   int npage, int prot, unsigned long *phys_pfn);
-void vfio_unpin_pages(struct vfio_device *device, unsigned long *user_pfn,
-                     int npage);
+void vfio_unpin_pages(struct vfio_device *device, dma_addr_t iova, int npage);
 int vfio_dma_rw(struct vfio_device *device, dma_addr_t user_iova,
                void *data, size_t len, bool write);