[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20201116110030.32335-7-eric.auger@redhat.com>
Date: Mon, 16 Nov 2020 12:00:23 +0100
From: Eric Auger <eric.auger@...hat.com>
To: eric.auger.pro@...il.com, eric.auger@...hat.com,
iommu@...ts.linux-foundation.org, linux-kernel@...r.kernel.org,
kvm@...r.kernel.org, kvmarm@...ts.cs.columbia.edu, will@...nel.org,
joro@...tes.org, maz@...nel.org, robin.murphy@....com,
alex.williamson@...hat.com
Cc: jean-philippe@...aro.org, zhangfei.gao@...aro.org,
zhangfei.gao@...il.com, vivek.gautam@....com,
shameerali.kolothum.thodi@...wei.com,
jacob.jun.pan@...ux.intel.com, yi.l.liu@...el.com, tn@...ihalf.com,
nicoleotsuka@...il.com, yuzenghui@...wei.com
Subject: [PATCH v11 06/13] vfio/pci: Allow to mmap the fault queue
The DMA FAULT region contains the fault ring buffer.
There is benefit to let the userspace mmap this area.
Expose this mmappable area through a sparse mmap entry
and implement the mmap operation.
Signed-off-by: Eric Auger <eric.auger@...hat.com>
---
v8 -> v9:
- remove unused index local variable in vfio_pci_fault_mmap
---
drivers/vfio/pci/vfio_pci.c | 61 +++++++++++++++++++++++++++++++++++--
1 file changed, 58 insertions(+), 3 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index b39d6ed66c71..2a6cc1a87323 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -318,21 +318,75 @@ static void vfio_pci_dma_fault_release(struct vfio_pci_device *vdev,
kfree(vdev->fault_pages);
}
+static int vfio_pci_dma_fault_mmap(struct vfio_pci_device *vdev,
+ struct vfio_pci_region *region,
+ struct vm_area_struct *vma)
+{
+ u64 phys_len, req_len, pgoff, req_start;
+ unsigned long long addr;
+ unsigned int ret;
+
+ phys_len = region->size;
+
+ req_len = vma->vm_end - vma->vm_start;
+ pgoff = vma->vm_pgoff &
+ ((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
+ req_start = pgoff << PAGE_SHIFT;
+
+ /* only the second page of the producer fault region is mmappable */
+ if (req_start < PAGE_SIZE)
+ return -EINVAL;
+
+ if (req_start + req_len > phys_len)
+ return -EINVAL;
+
+ addr = virt_to_phys(vdev->fault_pages);
+ vma->vm_private_data = vdev;
+ vma->vm_pgoff = (addr >> PAGE_SHIFT) + pgoff;
+
+ ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ req_len, vma->vm_page_prot);
+ return ret;
+}
+
static int vfio_pci_dma_fault_add_capability(struct vfio_pci_device *vdev,
struct vfio_pci_region *region,
struct vfio_info_cap *caps)
{
+ struct vfio_region_info_cap_sparse_mmap *sparse = NULL;
struct vfio_region_info_cap_fault cap = {
.header.id = VFIO_REGION_INFO_CAP_DMA_FAULT,
.header.version = 1,
.version = 1,
};
- return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
+ size_t size = sizeof(*sparse) + sizeof(*sparse->areas);
+ int ret;
+
+ ret = vfio_info_add_capability(caps, &cap.header, sizeof(cap));
+ if (ret)
+ return ret;
+
+ sparse = kzalloc(size, GFP_KERNEL);
+ if (!sparse)
+ return -ENOMEM;
+
+ sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
+ sparse->header.version = 1;
+ sparse->nr_areas = 1;
+ sparse->areas[0].offset = PAGE_SIZE;
+ sparse->areas[0].size = region->size - PAGE_SIZE;
+
+ ret = vfio_info_add_capability(caps, &sparse->header, size);
+ if (ret)
+ kfree(sparse);
+
+ return ret;
}
static const struct vfio_pci_regops vfio_pci_dma_fault_regops = {
.rw = vfio_pci_dma_fault_rw,
.release = vfio_pci_dma_fault_release,
+ .mmap = vfio_pci_dma_fault_mmap,
.add_capability = vfio_pci_dma_fault_add_capability,
};
@@ -403,7 +457,8 @@ static int vfio_pci_dma_fault_init(struct vfio_pci_device *vdev)
VFIO_REGION_TYPE_NESTED,
VFIO_REGION_SUBTYPE_NESTED_DMA_FAULT,
&vfio_pci_dma_fault_regops, size,
- VFIO_REGION_INFO_FLAG_READ | VFIO_REGION_INFO_FLAG_WRITE,
+ VFIO_REGION_INFO_FLAG_READ | VFIO_REGION_INFO_FLAG_WRITE |
+ VFIO_REGION_INFO_FLAG_MMAP,
vdev->fault_pages);
if (ret)
goto out;
@@ -411,7 +466,7 @@ static int vfio_pci_dma_fault_init(struct vfio_pci_device *vdev)
header = (struct vfio_region_dma_fault *)vdev->fault_pages;
header->entry_size = sizeof(struct iommu_fault);
header->nb_entries = DMA_FAULT_RING_LENGTH;
- header->offset = sizeof(struct vfio_region_dma_fault);
+ header->offset = PAGE_SIZE;
ret = iommu_register_device_fault_handler(&vdev->pdev->dev,
vfio_pci_iommu_dev_fault_handler,
--
2.21.3
Powered by blists - more mailing lists