Commit a9cf69d0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfio-v6.0-rc1' of https://github.com/awilliam/linux-vfio

Pull VFIO updates from Alex Williamson:

 - Cleanup use of extern in function prototypes (Alex Williamson)

 - Simplify bus_type usage and convert to device IOMMU interfaces (Robin
   Murphy)

 - Check missed return value and fix comment typos (Bo Liu)

 - Split migration ops from device ops and fix races in mlx5 migration
   support (Yishai Hadas)

 - Fix missed return value check in noiommu support (Liam Ni)

 - Hardening to clear buffer pointer to avoid use-after-free (Schspa
   Shi)

 - Remove requirement that only the same mm can unmap a previously
   mapped range (Li Zhe)

 - Adjust semaphore release vs device open counter (Yi Liu)

 - Remove unused arg from SPAPR support code (Deming Wang)

 - Rework vfio-ccw driver to better fit new mdev framework (Eric Farman,
   Michael Kawano)

 - Replace DMA unmap notifier with callbacks (Jason Gunthorpe)

 - Clarify SPAPR support comment relative to iommu_ops (Alexey
   Kardashevskiy)

 - Revise page pinning API towards compatibility with future iommufd
   support (Nicolin Chen)

 - Resolve issues in vfio-ccw, including use of DMA unmap callback (Eric
   Farman)

* tag 'vfio-v6.0-rc1' of https://github.com/awilliam/linux-vfio: (40 commits)
  vfio/pci: fix the wrong word
  vfio/ccw: Check return code from subchannel quiesce
  vfio/ccw: Remove FSM Close from remove handlers
  vfio/ccw: Add length to DMA_UNMAP checks
  vfio: Replace phys_pfn with pages for vfio_pin_pages()
  vfio/ccw: Add kmap_local_page() for memcpy
  vfio: Rename user_iova of vfio_dma_rw()
  vfio/ccw: Change pa_pfn list to pa_iova list
  vfio/ap: Change saved_pfn to saved_iova
  vfio: Pass in starting IOVA to vfio_pin/unpin_pages API
  vfio/ccw: Only pass in contiguous pages
  vfio/ap: Pass in physical address of ind to ap_aqic()
  drm/i915/gvt: Replace roundup with DIV_ROUND_UP
  vfio: Make vfio_unpin_pages() return void
  vfio/spapr_tce: Fix the comment
  vfio: Replace the iommu notifier with a device list
  vfio: Replace the DMA unmapping notifier with a callback
  vfio/ccw: Move FSM open/close to MDEV open/close
  vfio/ccw: Refactor vfio_ccw_mdev_reset
  vfio/ccw: Create a CLOSE FSM event
  ...
parents 6614a3c3 099fd2c2
Loading
Loading
Loading
Loading
+8 −8
Original line number Diff line number Diff line
@@ -112,11 +112,11 @@ to register and unregister itself with the core driver:

* Register::

    extern int  mdev_register_driver(struct mdev_driver *drv);
    int mdev_register_driver(struct mdev_driver *drv);

* Unregister::

    extern void mdev_unregister_driver(struct mdev_driver *drv);
    void mdev_unregister_driver(struct mdev_driver *drv);

The mediated bus driver's probe function should create a vfio_device on top of
the mdev_device and connect it to an appropriate implementation of
@@ -125,7 +125,7 @@ vfio_device_ops.
When a driver wants to add the GUID creation sysfs to an existing device it has
probe'd to then it should call::

	extern int  mdev_register_device(struct device *dev,
    int mdev_register_device(struct device *dev,
                             struct mdev_driver *mdev_driver);

This will provide the 'mdev_supported_types/XX/create' files which can then be
@@ -134,7 +134,7 @@ attached to the specified driver.

When the driver needs to remove itself it calls::

	extern void mdev_unregister_device(struct device *dev);
    void mdev_unregister_device(struct device *dev);

Which will unbind and destroy all the created mdevs and remove the sysfs files.

@@ -260,10 +260,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 npage, int prot, unsigned long *phys_pfn);
	int vfio_pin_pages(struct vfio_device *device, dma_addr_t iova,
				  int npage, int prot, struct page **pages);

	int 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
+3 −3
Original line number Diff line number Diff line
@@ -227,13 +227,13 @@ struct ap_qirq_ctrl {
 * ap_aqic(): Control interruption for a specific AP.
 * @qid: The AP queue number
 * @qirqctrl: struct ap_qirq_ctrl (64 bit value)
 * @ind: The notification indicator byte
 * @pa_ind: Physical address of the notification indicator byte
 *
 * Returns AP queue status.
 */
static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
					     struct ap_qirq_ctrl qirqctrl,
					     void *ind)
					     phys_addr_t pa_ind)
{
	unsigned long reg0 = qid | (3UL << 24);  /* fc 3UL is AQIC */
	union {
@@ -241,7 +241,7 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
		struct ap_qirq_ctrl qirqctrl;
		struct ap_queue_status status;
	} reg1;
	unsigned long reg2 = virt_to_phys(ind);
	unsigned long reg2 = pa_ind;

	reg1.qirqctrl = qirqctrl;

+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;
+32 −88
Original line number Diff line number Diff line
@@ -231,57 +231,38 @@ 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)
{
	struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
	int total_pages;
	int npage;
	int ret;

	total_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE;

	for (npage = 0; npage < total_pages; npage++) {
		unsigned long cur_gfn = gfn + npage;

		ret = vfio_unpin_pages(&vgpu->vfio_device, &cur_gfn, 1);
		drm_WARN_ON(&i915->drm, ret != 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. */
static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
		unsigned long size, struct page **page)
{
	unsigned long base_pfn = 0;
	int total_pages;
	int total_pages = DIV_ROUND_UP(size, PAGE_SIZE);
	struct page *base_page = NULL;
	int npage;
	int ret;

	total_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE;
	/*
	 * We pin the pages one-by-one to avoid allocating a big arrary
	 * on stack to hold pfns.
	 */
	for (npage = 0; npage < total_pages; npage++) {
		unsigned long cur_gfn = gfn + npage;
		unsigned long pfn;
		dma_addr_t cur_iova = (gfn + npage) << PAGE_SHIFT;
		struct page *cur_page;

		ret = vfio_pin_pages(&vgpu->vfio_device, &cur_gfn, 1,
				     IOMMU_READ | IOMMU_WRITE, &pfn);
		ret = vfio_pin_pages(&vgpu->vfio_device, cur_iova, 1,
				     IOMMU_READ | IOMMU_WRITE, &cur_page);
		if (ret != 1) {
			gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx, ret %d\n",
				     cur_gfn, ret);
			goto err;
		}

		if (!pfn_valid(pfn)) {
			gvt_vgpu_err("pfn 0x%lx is not mem backed\n", pfn);
			npage++;
			ret = -EFAULT;
			gvt_vgpu_err("vfio_pin_pages failed for iova %pad, ret %d\n",
				     &cur_iova, ret);
			goto err;
		}

		if (npage == 0)
			base_pfn = pfn;
		else if (base_pfn + npage != pfn) {
			base_page = cur_page;
		else if (base_page + npage != cur_page) {
			gvt_vgpu_err("The pages are not continuous\n");
			ret = -EINVAL;
			npage++;
@@ -289,7 +270,7 @@ static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
		}
	}

	*page = pfn_to_page(base_pfn);
	*page = base_page;
	return 0;
err:
	gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE);
@@ -729,19 +710,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 +731,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 +755,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 +787,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 +803,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 +812,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 +1553,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)
+0 −1
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@
 */

#include <linux/vfio.h>
#include <linux/mdev.h>

#include "vfio_ccw_private.h"

Loading