Commit ce4b4657 authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Alex Williamson
Browse files

vfio: Replace the DMA unmapping notifier with a callback



Instead of having drivers register the notifier with explicit code just
have them provide a dma_unmap callback op in their driver ops and rely on
the core code to wire it up.

Suggested-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarTony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: default avatarEric Farman <farman@linux.ibm.com>
Reviewed-by: default avatarZhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/1-v4-681e038e30fd+78-vfio_unmap_notif_jgg@nvidia.com


Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 2a8ed7ef
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -226,7 +226,6 @@ struct intel_vgpu {
	unsigned long nr_cache_entries;
	struct mutex cache_lock;

	struct notifier_block iommu_notifier;
	atomic_t released;

	struct kvm_page_track_notifier_node track_node;
+19 −56
Original line number Diff line number Diff line
@@ -729,19 +729,13 @@ int intel_gvt_set_edid(struct intel_vgpu *vgpu, int port_num)
	return ret;
}

static int intel_vgpu_iommu_notifier(struct notifier_block *nb,
				     unsigned long action, void *data)
static void intel_vgpu_dma_unmap(struct vfio_device *vfio_dev, u64 iova,
				 u64 length)
{
	struct intel_vgpu *vgpu =
		container_of(nb, struct intel_vgpu, iommu_notifier);

	if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
		struct vfio_iommu_type1_dma_unmap *unmap = data;
	struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
	struct gvt_dma *entry;
		unsigned long iov_pfn, end_iov_pfn;

		iov_pfn = unmap->iova >> PAGE_SHIFT;
		end_iov_pfn = iov_pfn + unmap->size / PAGE_SIZE;
	u64 iov_pfn = iova >> PAGE_SHIFT;
	u64 end_iov_pfn = iov_pfn + length / PAGE_SIZE;

	mutex_lock(&vgpu->cache_lock);
	for (; iov_pfn < end_iov_pfn; iov_pfn++) {
@@ -756,9 +750,6 @@ static int intel_vgpu_iommu_notifier(struct notifier_block *nb,
	mutex_unlock(&vgpu->cache_lock);
}

	return NOTIFY_OK;
}

static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu)
{
	struct intel_vgpu *itr;
@@ -783,36 +774,20 @@ static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu)
static int intel_vgpu_open_device(struct vfio_device *vfio_dev)
{
	struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
	unsigned long events;
	int ret;

	vgpu->iommu_notifier.notifier_call = intel_vgpu_iommu_notifier;

	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
	ret = vfio_register_notifier(vfio_dev, VFIO_IOMMU_NOTIFY, &events,
				     &vgpu->iommu_notifier);
	if (ret != 0) {
		gvt_vgpu_err("vfio_register_notifier for iommu failed: %d\n",
			ret);
		goto out;
	}

	ret = -EEXIST;
	if (vgpu->attached)
		goto undo_iommu;
		return -EEXIST;

	ret = -ESRCH;
	if (!vgpu->vfio_device.kvm ||
	    vgpu->vfio_device.kvm->mm != current->mm) {
		gvt_vgpu_err("KVM is required to use Intel vGPU\n");
		goto undo_iommu;
		return -ESRCH;
	}

	kvm_get_kvm(vgpu->vfio_device.kvm);

	ret = -EEXIST;
	if (__kvmgt_vgpu_exist(vgpu))
		goto undo_iommu;
		return -EEXIST;

	vgpu->attached = true;

@@ -831,12 +806,6 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev)

	atomic_set(&vgpu->released, 0);
	return 0;

undo_iommu:
	vfio_unregister_notifier(vfio_dev, VFIO_IOMMU_NOTIFY,
				 &vgpu->iommu_notifier);
out:
	return ret;
}

static void intel_vgpu_release_msi_eventfd_ctx(struct intel_vgpu *vgpu)
@@ -853,8 +822,6 @@ static void intel_vgpu_release_msi_eventfd_ctx(struct intel_vgpu *vgpu)
static void intel_vgpu_close_device(struct vfio_device *vfio_dev)
{
	struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
	int ret;

	if (!vgpu->attached)
		return;
@@ -864,11 +831,6 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev)

	intel_gvt_release_vgpu(vgpu);

	ret = vfio_unregister_notifier(&vgpu->vfio_device, VFIO_IOMMU_NOTIFY,
				       &vgpu->iommu_notifier);
	drm_WARN(&i915->drm, ret,
		 "vfio_unregister_notifier for iommu failed: %d\n", ret);

	debugfs_remove(debugfs_lookup(KVMGT_DEBUGFS_FILENAME, vgpu->debugfs));

	kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm,
@@ -1610,6 +1572,7 @@ static const struct vfio_device_ops intel_vgpu_dev_ops = {
	.write		= intel_vgpu_write,
	.mmap		= intel_vgpu_mmap,
	.ioctl		= intel_vgpu_ioctl,
	.dma_unmap	= intel_vgpu_dma_unmap,
};

static int intel_vgpu_probe(struct mdev_device *mdev)
+8 −31
Original line number Diff line number Diff line
@@ -33,30 +33,16 @@ static int vfio_ccw_mdev_reset(struct vfio_ccw_private *private)
	return 0;
}

static int vfio_ccw_mdev_notifier(struct notifier_block *nb,
				  unsigned long action,
				  void *data)
static void vfio_ccw_dma_unmap(struct vfio_device *vdev, u64 iova, u64 length)
{
	struct vfio_ccw_private *private =
		container_of(nb, struct vfio_ccw_private, nb);

	/*
	 * Vendor drivers MUST unpin pages in response to an
	 * invalidation.
	 */
	if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
		struct vfio_iommu_type1_dma_unmap *unmap = data;

		if (!cp_iova_pinned(&private->cp, unmap->iova))
			return NOTIFY_OK;

		if (vfio_ccw_mdev_reset(private))
			return NOTIFY_BAD;
		container_of(vdev, struct vfio_ccw_private, vdev);

		return NOTIFY_OK;
	}
	/* Drivers MUST unpin pages in response to an invalidation. */
	if (!cp_iova_pinned(&private->cp, iova))
		return;

	return NOTIFY_DONE;
	vfio_ccw_mdev_reset(private);
}

static ssize_t name_show(struct mdev_type *mtype,
@@ -154,23 +140,15 @@ static int vfio_ccw_mdev_open_device(struct vfio_device *vdev)
{
	struct vfio_ccw_private *private =
		container_of(vdev, struct vfio_ccw_private, vdev);
	unsigned long events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
	int ret;

	/* Device cannot simply be opened again from this state */
	if (private->state == VFIO_CCW_STATE_NOT_OPER)
		return -EINVAL;

	private->nb.notifier_call = vfio_ccw_mdev_notifier;

	ret = vfio_register_notifier(vdev, VFIO_IOMMU_NOTIFY,
				     &events, &private->nb);
	if (ret)
		return ret;

	ret = vfio_ccw_register_async_dev_regions(private);
	if (ret)
		goto out_unregister;
		return ret;

	ret = vfio_ccw_register_schib_dev_regions(private);
	if (ret)
@@ -190,7 +168,6 @@ static int vfio_ccw_mdev_open_device(struct vfio_device *vdev)

out_unregister:
	vfio_ccw_unregister_dev_regions(private);
	vfio_unregister_notifier(vdev, VFIO_IOMMU_NOTIFY, &private->nb);
	return ret;
}

@@ -201,7 +178,6 @@ static void vfio_ccw_mdev_close_device(struct vfio_device *vdev)

	vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
	vfio_ccw_unregister_dev_regions(private);
	vfio_unregister_notifier(vdev, VFIO_IOMMU_NOTIFY, &private->nb);
}

static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private,
@@ -624,6 +600,7 @@ static const struct vfio_device_ops vfio_ccw_dev_ops = {
	.write = vfio_ccw_mdev_write,
	.ioctl = vfio_ccw_mdev_ioctl,
	.request = vfio_ccw_mdev_request,
	.dma_unmap = vfio_ccw_dma_unmap,
};

struct mdev_driver vfio_ccw_mdev_driver = {
+0 −2
Original line number Diff line number Diff line
@@ -73,7 +73,6 @@ struct vfio_ccw_crw {
 * @state: internal state of the device
 * @completion: synchronization helper of the I/O completion
 * @avail: available for creating a mediated device
 * @nb: notifier for vfio events
 * @io_region: MMIO region to input/output I/O arguments/results
 * @io_mutex: protect against concurrent update of I/O regions
 * @region: additional regions for other subchannel operations
@@ -96,7 +95,6 @@ struct vfio_ccw_private {
	int			state;
	struct completion	*completion;
	atomic_t		avail;
	struct notifier_block	nb;
	struct ccw_io_region	*io_region;
	struct mutex		io_mutex;
	struct vfio_ccw_region *region;
+8 −45
Original line number Diff line number Diff line
@@ -1226,34 +1226,14 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
	return 0;
}

/**
 * vfio_ap_mdev_iommu_notifier - IOMMU notifier callback
 *
 * @nb: The notifier block
 * @action: Action to be taken
 * @data: data associated with the request
 *
 * For an UNMAP request, unpin the guest IOVA (the NIB guest address we
 * pinned before). Other requests are ignored.
 *
 * Return: for an UNMAP request, NOFITY_OK; otherwise NOTIFY_DONE.
 */
static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb,
				       unsigned long action, void *data)
static void vfio_ap_mdev_dma_unmap(struct vfio_device *vdev, u64 iova,
				   u64 length)
{
	struct ap_matrix_mdev *matrix_mdev;

	matrix_mdev = container_of(nb, struct ap_matrix_mdev, iommu_notifier);

	if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
		struct vfio_iommu_type1_dma_unmap *unmap = data;
		unsigned long g_pfn = unmap->iova >> PAGE_SHIFT;
	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);
		return NOTIFY_OK;
	}

	return NOTIFY_DONE;
}

/**
@@ -1380,27 +1360,11 @@ static int vfio_ap_mdev_open_device(struct vfio_device *vdev)
{
	struct ap_matrix_mdev *matrix_mdev =
		container_of(vdev, struct ap_matrix_mdev, vdev);
	unsigned long events;
	int ret;

	if (!vdev->kvm)
		return -EINVAL;

	ret = vfio_ap_mdev_set_kvm(matrix_mdev, vdev->kvm);
	if (ret)
		return ret;

	matrix_mdev->iommu_notifier.notifier_call = vfio_ap_mdev_iommu_notifier;
	events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
	ret = vfio_register_notifier(vdev, VFIO_IOMMU_NOTIFY, &events,
				     &matrix_mdev->iommu_notifier);
	if (ret)
		goto err_kvm;
	return 0;

err_kvm:
	vfio_ap_mdev_unset_kvm(matrix_mdev);
	return ret;
	return vfio_ap_mdev_set_kvm(matrix_mdev, vdev->kvm);
}

static void vfio_ap_mdev_close_device(struct vfio_device *vdev)
@@ -1408,8 +1372,6 @@ static void vfio_ap_mdev_close_device(struct vfio_device *vdev)
	struct ap_matrix_mdev *matrix_mdev =
		container_of(vdev, struct ap_matrix_mdev, vdev);

	vfio_unregister_notifier(vdev, VFIO_IOMMU_NOTIFY,
				 &matrix_mdev->iommu_notifier);
	vfio_ap_mdev_unset_kvm(matrix_mdev);
}

@@ -1461,6 +1423,7 @@ static const struct vfio_device_ops vfio_ap_matrix_dev_ops = {
	.open_device = vfio_ap_mdev_open_device,
	.close_device = vfio_ap_mdev_close_device,
	.ioctl = vfio_ap_mdev_ioctl,
	.dma_unmap = vfio_ap_mdev_dma_unmap,
};

static struct mdev_driver vfio_ap_matrix_driver = {
Loading