Skip to content

Commit

Permalink
Merge tag 'vfio-v6.0-rc1' of https://github.com/awilliam/linux-vfio
Browse files Browse the repository at this point in the history
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
  ...
  • Loading branch information
torvalds committed Aug 6, 2022
2 parents 6614a3c + 099fd2c commit a9cf69d
Show file tree
Hide file tree
Showing 29 changed files with 659 additions and 768 deletions.
16 changes: 8 additions & 8 deletions Documentation/driver-api/vfio-mediated-device.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -125,16 +125,16 @@ 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,
struct mdev_driver *mdev_driver);
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
used to trigger the creation of a mdev_device. The created mdev_device will be
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.

Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions arch/s390/include/asm/ap.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,21 +227,21 @@ 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 {
unsigned long value;
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;

Expand Down
1 change: 0 additions & 1 deletion drivers/gpu/drm/i915/gvt/gvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
120 changes: 32 additions & 88 deletions drivers/gpu/drm/i915/gvt/kvmgt.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,65 +231,46 @@ 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++;
goto err;
}
}

*page = pfn_to_page(base_pfn);
*page = base_page;
return 0;
err:
gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE);
Expand Down Expand Up @@ -729,34 +710,25 @@ 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 gvt_dma *entry;
unsigned long iov_pfn, end_iov_pfn;
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
struct gvt_dma *entry;
u64 iov_pfn = iova >> PAGE_SHIFT;
u64 end_iov_pfn = iov_pfn + length / PAGE_SIZE;

iov_pfn = unmap->iova >> PAGE_SHIFT;
end_iov_pfn = iov_pfn + unmap->size / PAGE_SIZE;
mutex_lock(&vgpu->cache_lock);
for (; iov_pfn < end_iov_pfn; iov_pfn++) {
entry = __gvt_cache_find_gfn(vgpu, iov_pfn);
if (!entry)
continue;

mutex_lock(&vgpu->cache_lock);
for (; iov_pfn < end_iov_pfn; iov_pfn++) {
entry = __gvt_cache_find_gfn(vgpu, iov_pfn);
if (!entry)
continue;

gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr,
entry->size);
__gvt_cache_remove_entry(vgpu, entry);
}
mutex_unlock(&vgpu->cache_lock);
gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr,
entry->size);
__gvt_cache_remove_entry(vgpu, entry);
}

return NOTIFY_OK;
mutex_unlock(&vgpu->cache_lock);
}

static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu)
Expand All @@ -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;

Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
1 change: 0 additions & 1 deletion drivers/s390/cio/vfio_ccw_async.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*/

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

#include "vfio_ccw_private.h"

Expand Down
Loading

0 comments on commit a9cf69d

Please sign in to comment.