Commit a9cf69d0 authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -112,11 +112,11 @@ to register and unregister itself with the core driver: ...@@ -112,11 +112,11 @@ to register and unregister itself with the core driver:
* Register:: * Register::
extern int mdev_register_driver(struct mdev_driver *drv); int mdev_register_driver(struct mdev_driver *drv);
* Unregister:: * 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 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 the mdev_device and connect it to an appropriate implementation of
...@@ -125,8 +125,8 @@ vfio_device_ops. ...@@ -125,8 +125,8 @@ vfio_device_ops.
When a driver wants to add the GUID creation sysfs to an existing device it has When a driver wants to add the GUID creation sysfs to an existing device it has
probe'd to then it should call:: 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); struct mdev_driver *mdev_driver);
This will provide the 'mdev_supported_types/XX/create' files which can then be 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 used to trigger the creation of a mdev_device. The created mdev_device will be
...@@ -134,7 +134,7 @@ attached to the specified driver. ...@@ -134,7 +134,7 @@ attached to the specified driver.
When the driver needs to remove itself it calls:: 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. Which will unbind and destroy all the created mdevs and remove the sysfs files.
...@@ -260,10 +260,10 @@ Translation APIs for Mediated Devices ...@@ -260,10 +260,10 @@ Translation APIs for Mediated Devices
The following APIs are provided for translating user pfn to host pfn in a VFIO The following APIs are provided for translating user pfn to host pfn in a VFIO
driver:: 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); 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); int npage);
These functions call back into the back-end IOMMU module by using the pin_pages These functions call back into the back-end IOMMU module by using the pin_pages
......
...@@ -227,13 +227,13 @@ struct ap_qirq_ctrl { ...@@ -227,13 +227,13 @@ struct ap_qirq_ctrl {
* ap_aqic(): Control interruption for a specific AP. * ap_aqic(): Control interruption for a specific AP.
* @qid: The AP queue number * @qid: The AP queue number
* @qirqctrl: struct ap_qirq_ctrl (64 bit value) * @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. * Returns AP queue status.
*/ */
static inline struct ap_queue_status ap_aqic(ap_qid_t qid, static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
struct ap_qirq_ctrl qirqctrl, struct ap_qirq_ctrl qirqctrl,
void *ind) phys_addr_t pa_ind)
{ {
unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */ unsigned long reg0 = qid | (3UL << 24); /* fc 3UL is AQIC */
union { union {
...@@ -241,7 +241,7 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid, ...@@ -241,7 +241,7 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
struct ap_qirq_ctrl qirqctrl; struct ap_qirq_ctrl qirqctrl;
struct ap_queue_status status; struct ap_queue_status status;
} reg1; } reg1;
unsigned long reg2 = virt_to_phys(ind); unsigned long reg2 = pa_ind;
reg1.qirqctrl = qirqctrl; reg1.qirqctrl = qirqctrl;
......
...@@ -226,7 +226,6 @@ struct intel_vgpu { ...@@ -226,7 +226,6 @@ struct intel_vgpu {
unsigned long nr_cache_entries; unsigned long nr_cache_entries;
struct mutex cache_lock; struct mutex cache_lock;
struct notifier_block iommu_notifier;
atomic_t released; atomic_t released;
struct kvm_page_track_notifier_node track_node; struct kvm_page_track_notifier_node track_node;
......
...@@ -231,57 +231,38 @@ static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt) ...@@ -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, static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
unsigned long size) unsigned long size)
{ {
struct drm_i915_private *i915 = vgpu->gvt->gt->i915; vfio_unpin_pages(&vgpu->vfio_device, gfn << PAGE_SHIFT,
int total_pages; DIV_ROUND_UP(size, PAGE_SIZE));
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);
}
} }
/* Pin a normal or compound guest page for dma. */ /* Pin a normal or compound guest page for dma. */
static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
unsigned long size, struct page **page) unsigned long size, struct page **page)
{ {
unsigned long base_pfn = 0; int total_pages = DIV_ROUND_UP(size, PAGE_SIZE);
int total_pages; struct page *base_page = NULL;
int npage; int npage;
int ret; int ret;
total_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE;
/* /*
* We pin the pages one-by-one to avoid allocating a big arrary * We pin the pages one-by-one to avoid allocating a big arrary
* on stack to hold pfns. * on stack to hold pfns.
*/ */
for (npage = 0; npage < total_pages; npage++) { 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; struct page *cur_page;
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); IOMMU_READ | IOMMU_WRITE, &cur_page);
if (ret != 1) { if (ret != 1) {
gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx, ret %d\n", gvt_vgpu_err("vfio_pin_pages failed for iova %pad, ret %d\n",
cur_gfn, ret); &cur_iova, ret);
goto err;
}
if (!pfn_valid(pfn)) {
gvt_vgpu_err("pfn 0x%lx is not mem backed\n", pfn);
npage++;
ret = -EFAULT;
goto err; goto err;
} }
if (npage == 0) if (npage == 0)
base_pfn = pfn; base_page = cur_page;
else if (base_pfn + npage != pfn) { else if (base_page + npage != cur_page) {
gvt_vgpu_err("The pages are not continuous\n"); gvt_vgpu_err("The pages are not continuous\n");
ret = -EINVAL; ret = -EINVAL;
npage++; npage++;
...@@ -289,7 +270,7 @@ static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn, ...@@ -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; return 0;
err: err:
gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE); gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE);
...@@ -729,34 +710,25 @@ int intel_gvt_set_edid(struct intel_vgpu *vgpu, int port_num) ...@@ -729,34 +710,25 @@ int intel_gvt_set_edid(struct intel_vgpu *vgpu, int port_num)
return ret; return ret;
} }
static int intel_vgpu_iommu_notifier(struct notifier_block *nb, static void intel_vgpu_dma_unmap(struct vfio_device *vfio_dev, u64 iova,
unsigned long action, void *data) u64 length)
{ {
struct intel_vgpu *vgpu = struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
container_of(nb, struct intel_vgpu, iommu_notifier); struct gvt_dma *entry;
u64 iov_pfn = iova >> PAGE_SHIFT;
if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) { u64 end_iov_pfn = iov_pfn + length / PAGE_SIZE;
struct vfio_iommu_type1_dma_unmap *unmap = data;
struct gvt_dma *entry;
unsigned long iov_pfn, end_iov_pfn;
iov_pfn = unmap->iova >> PAGE_SHIFT; mutex_lock(&vgpu->cache_lock);
end_iov_pfn = iov_pfn + unmap->size / PAGE_SIZE; for (; iov_pfn < end_iov_pfn; iov_pfn++) {
entry = __gvt_cache_find_gfn(vgpu, iov_pfn);
if (!entry)
continue;
mutex_lock(&vgpu->cache_lock); gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr,
for (; iov_pfn < end_iov_pfn; iov_pfn++) { entry->size);
entry = __gvt_cache_find_gfn(vgpu, iov_pfn); __gvt_cache_remove_entry(vgpu, entry);
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);
} }
mutex_unlock(&vgpu->cache_lock);
return NOTIFY_OK;
} }
static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu) static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu)
...@@ -783,36 +755,20 @@ static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu) ...@@ -783,36 +755,20 @@ static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu)
static int intel_vgpu_open_device(struct vfio_device *vfio_dev) static int intel_vgpu_open_device(struct vfio_device *vfio_dev)
{ {
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(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) if (vgpu->attached)
goto undo_iommu; return -EEXIST;
ret = -ESRCH;
if (!vgpu->vfio_device.kvm || if (!vgpu->vfio_device.kvm ||
vgpu->vfio_device.kvm->mm != current->mm) { vgpu->vfio_device.kvm->mm != current->mm) {
gvt_vgpu_err("KVM is required to use Intel vGPU\n"); gvt_vgpu_err("KVM is required to use Intel vGPU\n");
goto undo_iommu; return -ESRCH;
} }
kvm_get_kvm(vgpu->vfio_device.kvm); kvm_get_kvm(vgpu->vfio_device.kvm);
ret = -EEXIST;
if (__kvmgt_vgpu_exist(vgpu)) if (__kvmgt_vgpu_exist(vgpu))
goto undo_iommu; return -EEXIST;
vgpu->attached = true; vgpu->attached = true;
...@@ -831,12 +787,6 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev) ...@@ -831,12 +787,6 @@ static int intel_vgpu_open_device(struct vfio_device *vfio_dev)
atomic_set(&vgpu->released, 0); atomic_set(&vgpu->released, 0);
return 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) 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) ...@@ -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) static void intel_vgpu_close_device(struct vfio_device *vfio_dev)
{ {
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(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) if (!vgpu->attached)
return; return;
...@@ -864,11 +812,6 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev) ...@@ -864,11 +812,6 @@ static void intel_vgpu_close_device(struct vfio_device *vfio_dev)
intel_gvt_release_vgpu(vgpu); 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)); debugfs_remove(debugfs_lookup(KVMGT_DEBUGFS_FILENAME, vgpu->debugfs));
kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm, kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm,
...@@ -1610,6 +1553,7 @@ static const struct vfio_device_ops intel_vgpu_dev_ops = { ...@@ -1610,6 +1553,7 @@ static const struct vfio_device_ops intel_vgpu_dev_ops = {
.write = intel_vgpu_write, .write = intel_vgpu_write,
.mmap = intel_vgpu_mmap, .mmap = intel_vgpu_mmap,
.ioctl = intel_vgpu_ioctl, .ioctl = intel_vgpu_ioctl,
.dma_unmap = intel_vgpu_dma_unmap,
}; };
static int intel_vgpu_probe(struct mdev_device *mdev) static int intel_vgpu_probe(struct mdev_device *mdev)
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
*/ */
#include <linux/vfio.h> #include <linux/vfio.h>
#include <linux/mdev.h>
#include "vfio_ccw_private.h" #include "vfio_ccw_private.h"
......
This diff is collapsed.
...@@ -41,11 +41,11 @@ struct channel_program { ...@@ -41,11 +41,11 @@ struct channel_program {
struct ccw1 *guest_cp; struct ccw1 *guest_cp;
}; };
extern int cp_init(struct channel_program *cp, union orb *orb); int cp_init(struct channel_program *cp, union orb *orb);
extern void cp_free(struct channel_program *cp); void cp_free(struct channel_program *cp);
extern int cp_prefetch(struct channel_program *cp); int cp_prefetch(struct channel_program *cp);
extern union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm); union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm);
extern void cp_update_scsw(struct channel_program *cp, union scsw *scsw); void cp_update_scsw(struct channel_program *cp, union scsw *scsw);
extern bool cp_iova_pinned(struct channel_program *cp, u64 iova); bool cp_iova_pinned(struct channel_program *cp, u64 iova, u64 length);
#endif #endif
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uuid.h>
#include <linux/mdev.h> #include <linux/mdev.h>
#include <asm/isc.h> #include <asm/isc.h>
...@@ -42,13 +41,6 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch) ...@@ -42,13 +41,6 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch)
DECLARE_COMPLETION_ONSTACK(completion); DECLARE_COMPLETION_ONSTACK(completion);
int iretry, ret = 0; int iretry, ret = 0;
spin_lock_irq(sch->lock);
if (!sch->schib.pmcw.ena)
goto out_unlock;
ret = cio_disable_subchannel(sch);
if (ret != -EBUSY)
goto out_unlock;
iretry = 255; iretry = 255;
do { do {
...@@ -75,9 +67,7 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch) ...@@ -75,9 +67,7 @@ int vfio_ccw_sch_quiesce(struct subchannel *sch)
spin_lock_irq(sch->lock); spin_lock_irq(sch->lock);
ret = cio_disable_subchannel(sch); ret = cio_disable_subchannel(sch);
} while (ret == -EBUSY); } while (ret == -EBUSY);
out_unlock:
private->state = VFIO_CCW_STATE_NOT_OPER;
spin_unlock_irq(sch->lock);
return ret; return ret;
} }
...@@ -107,9 +97,10 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) ...@@ -107,9 +97,10 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
/* /*
* Reset to IDLE only if processing of a channel program * Reset to IDLE only if processing of a channel program
* has finished. Do not overwrite a possible processing * has finished. Do not overwrite a possible processing
* state if the final interrupt was for HSCH or CSCH. * state if the interrupt was unsolicited, or if the final
* interrupt was for HSCH or CSCH.
*/ */
if (private->mdev && cp_is_finished) if (cp_is_finished)
private->state = VFIO_CCW_STATE_IDLE; private->state = VFIO_CCW_STATE_IDLE;
if (private->io_trigger) if (private->io_trigger)
...@@ -147,7 +138,7 @@ static struct vfio_ccw_private *vfio_ccw_alloc_private(struct subchannel *sch) ...@@ -147,7 +138,7 @@ static struct vfio_ccw_private *vfio_ccw_alloc_private(struct subchannel *sch)
private->sch = sch; private->sch = sch;
mutex_init(&private->io_mutex); mutex_init(&private->io_mutex);
private->state = VFIO_CCW_STATE_NOT_OPER; private->state = VFIO_CCW_STATE_STANDBY;
INIT_LIST_HEAD(&private->crw); INIT_LIST_HEAD(&private->crw);
INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo); INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
INIT_WORK(&private->crw_work, vfio_ccw_crw_todo); INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
...@@ -231,26 +222,15 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) ...@@ -231,26 +222,15 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
dev_set_drvdata(&sch->dev, private); dev_set_drvdata(&sch->dev, private);
spin_lock_irq(sch->lock); ret = mdev_register_device(&sch->dev, &vfio_ccw_mdev_driver);
sch->isc = VFIO_CCW_ISC;
ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
spin_unlock_irq(sch->lock);
if (ret) if (ret)
goto out_free; goto out_free;
private->state = VFIO_CCW_STATE_STANDBY;
ret = vfio_ccw_mdev_reg(sch);
if (ret)
goto out_disable;
VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n", VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n",
sch->schid.cssid, sch->schid.ssid, sch->schid.cssid, sch->schid.ssid,
sch->schid.sch_no); sch->schid.sch_no);
return 0; return 0;
out_disable:
cio_disable_subchannel(sch);
out_free: out_free:
dev_set_drvdata(&sch->dev, NULL); dev_set_drvdata(&sch->dev, NULL);
vfio_ccw_free_private(private); vfio_ccw_free_private(private);
...@@ -261,8 +241,7 @@ static void vfio_ccw_sch_remove(struct subchannel *sch) ...@@ -261,8 +241,7 @@ static void vfio_ccw_sch_remove(struct subchannel *sch)
{ {
struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
vfio_ccw_sch_quiesce(sch); mdev_unregister_device(&sch->dev);
vfio_ccw_mdev_unreg(sch);
dev_set_drvdata(&sch->dev, NULL); dev_set_drvdata(&sch->dev, NULL);
...@@ -275,7 +254,10 @@ static void vfio_ccw_sch_remove(struct subchannel *sch) ...@@ -275,7 +254,10 @@ static void vfio_ccw_sch_remove(struct subchannel *sch)
static void vfio_ccw_sch_shutdown(struct subchannel *sch) static void vfio_ccw_sch_shutdown(struct subchannel *sch)
{ {
vfio_ccw_sch_quiesce(sch); struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
} }
/** /**
...@@ -301,19 +283,11 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) ...@@ -301,19 +283,11 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
if (work_pending(&sch->todo_work)) if (work_pending(&sch->todo_work))
goto out_unlock; goto out_unlock;
if (cio_update_schib(sch)) {
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
rc = 0;
goto out_unlock;
}
private = dev_get_drvdata(&sch->dev);
if (private->state == VFIO_CCW_STATE_NOT_OPER) {
private->state = private->mdev ? VFIO_CCW_STATE_IDLE :
VFIO_CCW_STATE_STANDBY;
}
rc = 0; rc = 0;
if (cio_update_schib(sch))
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
out_unlock: out_unlock:
spin_unlock_irqrestore(sch->lock, flags); spin_unlock_irqrestore(sch->lock, flags);
...@@ -358,8 +332,8 @@ static int vfio_ccw_chp_event(struct subchannel *sch, ...@@ -358,8 +332,8 @@ static int vfio_ccw_chp_event(struct subchannel *sch,
return 0; return 0;
trace_vfio_ccw_chp_event(private->sch->schid, mask, event); trace_vfio_ccw_chp_event(private->sch->schid, mask, event);
VFIO_CCW_MSG_EVENT(2, "%pUl (%x.%x.%04x): mask=0x%x event=%d\n", VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: mask=0x%x event=%d\n",
mdev_uuid(private->mdev), sch->schid.cssid, sch->schid.cssid,
sch->schid.ssid, sch->schid.sch_no, sch->schid.ssid, sch->schid.sch_no,
mask, event); mask, event);
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
*/ */
#include <linux/vfio.h> #include <linux/vfio.h>
#include <linux/mdev.h>
#include <asm/isc.h>
#include "ioasm.h" #include "ioasm.h"
#include "vfio_ccw_private.h" #include "vfio_ccw_private.h"
...@@ -161,8 +162,12 @@ static void fsm_notoper(struct vfio_ccw_private *private, ...@@ -161,8 +162,12 @@ static void fsm_notoper(struct vfio_ccw_private *private,
{ {
struct subchannel *sch = private->sch; struct subchannel *sch = private->sch;
VFIO_CCW_TRACE_EVENT(2, "notoper"); VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: notoper event %x state %x\n",
VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); sch->schid.cssid,
sch->schid.ssid,
sch->schid.sch_no,
event,
private->state);
/* /*
* TODO: * TODO:
...@@ -170,6 +175,9 @@ static void fsm_notoper(struct vfio_ccw_private *private, ...@@ -170,6 +175,9 @@ static void fsm_notoper(struct vfio_ccw_private *private,
*/ */
css_sched_sch_todo(sch, SCH_TODO_UNREG); css_sched_sch_todo(sch, SCH_TODO_UNREG);
private->state = VFIO_CCW_STATE_NOT_OPER; private->state = VFIO_CCW_STATE_NOT_OPER;
/* This is usually handled during CLOSE event */
cp_free(&private->cp);
} }
/* /*
...@@ -242,7 +250,6 @@ static void fsm_io_request(struct vfio_ccw_private *private, ...@@ -242,7 +250,6 @@ static void fsm_io_request(struct vfio_ccw_private *private,
union orb *orb; union orb *orb;
union scsw *scsw = &private->scsw; union scsw *scsw = &private->scsw;
struct ccw_io_region *io_region = private->io_region; struct ccw_io_region *io_region = private->io_region;
struct mdev_device *mdev = private->mdev;
char *errstr = "request"; char *errstr = "request";
struct subchannel_id schid = get_schid(private); struct subchannel_id schid = get_schid(private);
...@@ -256,8 +263,8 @@ static void fsm_io_request(struct vfio_ccw_private *private, ...@@ -256,8 +263,8 @@ static void fsm_io_request(struct vfio_ccw_private *private,
if (orb->tm.b) { if (orb->tm.b) {
io_region->ret_code = -EOPNOTSUPP; io_region->ret_code = -EOPNOTSUPP;
VFIO_CCW_MSG_EVENT(2, VFIO_CCW_MSG_EVENT(2,
"%pUl (%x.%x.%04x): transport mode\n", "sch %x.%x.%04x: transport mode\n",
mdev_uuid(mdev), schid.cssid, schid.cssid,
schid.ssid, schid.sch_no); schid.ssid, schid.sch_no);
errstr = "transport mode"; errstr = "transport mode";
goto err_out; goto err_out;
...@@ -265,8 +272,8 @@ static void fsm_io_request(struct vfio_ccw_private *private, ...@@ -265,8 +272,8 @@ static void fsm_io_request(struct vfio_ccw_private *private,
io_region->ret_code = cp_init(&private->cp, orb); io_region->ret_code = cp_init(&private->cp, orb);
if (io_region->ret_code) { if (io_region->ret_code) {
VFIO_CCW_MSG_EVENT(2, VFIO_CCW_MSG_EVENT(2,
"%pUl (%x.%x.%04x): cp_init=%d\n", "sch %x.%x.%04x: cp_init=%d\n",
mdev_uuid(mdev), schid.cssid, schid.cssid,
schid.ssid, schid.sch_no, schid.ssid, schid.sch_no,
io_region->ret_code); io_region->ret_code);
errstr = "cp init"; errstr = "cp init";
...@@ -276,8 +283,8 @@ static void fsm_io_request(struct vfio_ccw_private *private, ...@@ -276,8 +283,8 @@ static void fsm_io_request(struct vfio_ccw_private *private,
io_region->ret_code = cp_prefetch(&private->cp); io_region->ret_code = cp_prefetch(&private->cp);
if (io_region->ret_code) { if (io_region->ret_code) {
VFIO_CCW_MSG_EVENT(2, VFIO_CCW_MSG_EVENT(2,
"%pUl (%x.%x.%04x): cp_prefetch=%d\n", "sch %x.%x.%04x: cp_prefetch=%d\n",
mdev_uuid(mdev), schid.cssid, schid.cssid,
schid.ssid, schid.sch_no, schid.ssid, schid.sch_no,
io_region->ret_code); io_region->ret_code);
errstr = "cp prefetch"; errstr = "cp prefetch";
...@@ -289,8 +296,8 @@ static void fsm_io_request(struct vfio_ccw_private *private, ...@@ -289,8 +296,8 @@ static void fsm_io_request(struct vfio_ccw_private *private,
io_region->ret_code = fsm_io_helper(private); io_region->ret_code = fsm_io_helper(private);
if (io_region->ret_code) { if (io_region->ret_code) {
VFIO_CCW_MSG_EVENT(2, VFIO_CCW_MSG_EVENT(2,
"%pUl (%x.%x.%04x): fsm_io_helper=%d\n", "sch %x.%x.%04x: fsm_io_helper=%d\n",
mdev_uuid(mdev), schid.cssid, schid.cssid,
schid.ssid, schid.sch_no, schid.ssid, schid.sch_no,
io_region->ret_code); io_region->ret_code);
errstr = "cp fsm_io_helper"; errstr = "cp fsm_io_helper";
...@@ -300,16 +307,16 @@ static void fsm_io_request(struct vfio_ccw_private *private, ...@@ -300,16 +307,16 @@ static void fsm_io_request(struct vfio_ccw_private *private,
return; return;
} else if (scsw->cmd.fctl & SCSW_FCTL_HALT_FUNC) { } else if (scsw->cmd.fctl & SCSW_FCTL_HALT_FUNC) {
VFIO_CCW_MSG_EVENT(2, VFIO_CCW_MSG_EVENT(2,
"%pUl (%x.%x.%04x): halt on io_region\n", "sch %x.%x.%04x: halt on io_region\n",
mdev_uuid(mdev), schid.cssid, schid.cssid,
schid.ssid, schid.sch_no); schid.ssid, schid.sch_no);
/* halt is handled via the async cmd region */ /* halt is handled via the async cmd region */
io_region->ret_code = -EOPNOTSUPP; io_region->ret_code = -EOPNOTSUPP;
goto err_out; goto err_out;
} else if (scsw->cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { } else if (scsw->cmd.fctl & SCSW_FCTL_CLEAR_FUNC) {
VFIO_CCW_MSG_EVENT(2, VFIO_CCW_MSG_EVENT(2,
"%pUl (%x.%x.%04x): clear on io_region\n", "sch %x.%x.%04x: clear on io_region\n",
mdev_uuid(mdev), schid.cssid, schid.cssid,
schid.ssid, schid.sch_no); schid.ssid, schid.sch_no);
/* clear is handled via the async cmd region */ /* clear is handled via the async cmd region */
io_region->ret_code = -EOPNOTSUPP; io_region->ret_code = -EOPNOTSUPP;
...@@ -366,6 +373,54 @@ static void fsm_irq(struct vfio_ccw_private *private, ...@@ -366,6 +373,54 @@ static void fsm_irq(struct vfio_ccw_private *private,
complete(private->completion); complete(private->completion);
} }
static void fsm_open(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
struct subchannel *sch = private->sch;
int ret;
spin_lock_irq(sch->lock);
sch->isc = VFIO_CCW_ISC;
ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
if (ret)
goto err_unlock;
private->state = VFIO_CCW_STATE_IDLE;
spin_unlock_irq(sch->lock);
return;
err_unlock:
spin_unlock_irq(sch->lock);
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
}
static void fsm_close(struct vfio_ccw_private *private,
enum vfio_ccw_event event)
{
struct subchannel *sch = private->sch;
int ret;
spin_lock_irq(sch->lock);
if (!sch->schib.pmcw.ena)
goto err_unlock;
ret = cio_disable_subchannel(sch);
if (ret == -EBUSY)
ret = vfio_ccw_sch_quiesce(sch);
if (ret)
goto err_unlock;
private->state = VFIO_CCW_STATE_STANDBY;
spin_unlock_irq(sch->lock);
cp_free(&private->cp);
return;
err_unlock:
spin_unlock_irq(sch->lock);
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
}
/* /*
* Device statemachine * Device statemachine
*/ */
...@@ -375,29 +430,39 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = { ...@@ -375,29 +430,39 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = {
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_error, [VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
[VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_error, [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_error,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_disabled_irq, [VFIO_CCW_EVENT_INTERRUPT] = fsm_disabled_irq,
[VFIO_CCW_EVENT_OPEN] = fsm_nop,
[VFIO_CCW_EVENT_CLOSE] = fsm_nop,
}, },
[VFIO_CCW_STATE_STANDBY] = { [VFIO_CCW_STATE_STANDBY] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_error, [VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
[VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_error, [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_error,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, [VFIO_CCW_EVENT_INTERRUPT] = fsm_disabled_irq,
[VFIO_CCW_EVENT_OPEN] = fsm_open,
[VFIO_CCW_EVENT_CLOSE] = fsm_notoper,
}, },
[VFIO_CCW_STATE_IDLE] = { [VFIO_CCW_STATE_IDLE] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_request, [VFIO_CCW_EVENT_IO_REQ] = fsm_io_request,
[VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_request, [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_request,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
[VFIO_CCW_EVENT_OPEN] = fsm_notoper,
[VFIO_CCW_EVENT_CLOSE] = fsm_close,
}, },
[VFIO_CCW_STATE_CP_PROCESSING] = { [VFIO_CCW_STATE_CP_PROCESSING] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_retry, [VFIO_CCW_EVENT_IO_REQ] = fsm_io_retry,
[VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_retry, [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_retry,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
[VFIO_CCW_EVENT_OPEN] = fsm_notoper,
[VFIO_CCW_EVENT_CLOSE] = fsm_close,
}, },
[VFIO_CCW_STATE_CP_PENDING] = { [VFIO_CCW_STATE_CP_PENDING] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper, [VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy, [VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy,
[VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_request, [VFIO_CCW_EVENT_ASYNC_REQ] = fsm_async_request,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq, [VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
[VFIO_CCW_EVENT_OPEN] = fsm_notoper,
[VFIO_CCW_EVENT_CLOSE] = fsm_close,
}, },
}; };
...@@ -21,54 +21,28 @@ static const struct vfio_device_ops vfio_ccw_dev_ops; ...@@ -21,54 +21,28 @@ static const struct vfio_device_ops vfio_ccw_dev_ops;
static int vfio_ccw_mdev_reset(struct vfio_ccw_private *private) static int vfio_ccw_mdev_reset(struct vfio_ccw_private *private)
{ {
struct subchannel *sch;
int ret;
sch = private->sch;
/* /*
* TODO: * If the FSM state is seen as Not Operational after closing
* In the cureent stage, some things like "no I/O running" and "no * and re-opening the mdev, return an error.
* interrupt pending" are clear, but we are not sure what other state
* we need to care about.
* There are still a lot more instructions need to be handled. We
* should come back here later.
*/ */
ret = vfio_ccw_sch_quiesce(sch); vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
if (ret) vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_OPEN);
return ret; if (private->state == VFIO_CCW_STATE_NOT_OPER)
return -EINVAL;
ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
if (!ret)
private->state = VFIO_CCW_STATE_IDLE;
return ret; return 0;
} }
static int vfio_ccw_mdev_notifier(struct notifier_block *nb, static void vfio_ccw_dma_unmap(struct vfio_device *vdev, u64 iova, u64 length)
unsigned long action,
void *data)
{ {
struct vfio_ccw_private *private = struct vfio_ccw_private *private =
container_of(nb, struct vfio_ccw_private, nb); container_of(vdev, struct vfio_ccw_private, vdev);
/*
* 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)) /* Drivers MUST unpin pages in response to an invalidation. */
return NOTIFY_BAD; if (!cp_iova_pinned(&private->cp, iova, length))
return;
cp_free(&private->cp); vfio_ccw_mdev_reset(private);
return NOTIFY_OK;
}
return NOTIFY_DONE;
} }
static ssize_t name_show(struct mdev_type *mtype, static ssize_t name_show(struct mdev_type *mtype,
...@@ -128,11 +102,8 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev) ...@@ -128,11 +102,8 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
vfio_init_group_dev(&private->vdev, &mdev->dev, vfio_init_group_dev(&private->vdev, &mdev->dev,
&vfio_ccw_dev_ops); &vfio_ccw_dev_ops);
private->mdev = mdev; VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: create\n",
private->state = VFIO_CCW_STATE_IDLE; private->sch->schid.cssid,
VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: create\n",
mdev_uuid(mdev), private->sch->schid.cssid,
private->sch->schid.ssid, private->sch->schid.ssid,
private->sch->schid.sch_no); private->sch->schid.sch_no);
...@@ -145,8 +116,6 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev) ...@@ -145,8 +116,6 @@ static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
err_atomic: err_atomic:
vfio_uninit_group_dev(&private->vdev); vfio_uninit_group_dev(&private->vdev);
atomic_inc(&private->avail); atomic_inc(&private->avail);
private->mdev = NULL;
private->state = VFIO_CCW_STATE_IDLE;
return ret; return ret;
} }
...@@ -154,23 +123,14 @@ static void vfio_ccw_mdev_remove(struct mdev_device *mdev) ...@@ -154,23 +123,14 @@ static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
{ {
struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent); struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent);
VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: remove\n", VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: remove\n",
mdev_uuid(mdev), private->sch->schid.cssid, private->sch->schid.cssid,
private->sch->schid.ssid, private->sch->schid.ssid,
private->sch->schid.sch_no); private->sch->schid.sch_no);
vfio_unregister_group_dev(&private->vdev); vfio_unregister_group_dev(&private->vdev);
if ((private->state != VFIO_CCW_STATE_NOT_OPER) &&
(private->state != VFIO_CCW_STATE_STANDBY)) {
if (!vfio_ccw_sch_quiesce(private->sch))
private->state = VFIO_CCW_STATE_STANDBY;
/* The state will be NOT_OPER on error. */
}
vfio_uninit_group_dev(&private->vdev); vfio_uninit_group_dev(&private->vdev);
cp_free(&private->cp);
private->mdev = NULL;
atomic_inc(&private->avail); atomic_inc(&private->avail);
} }
...@@ -178,19 +138,15 @@ static int vfio_ccw_mdev_open_device(struct vfio_device *vdev) ...@@ -178,19 +138,15 @@ static int vfio_ccw_mdev_open_device(struct vfio_device *vdev)
{ {
struct vfio_ccw_private *private = struct vfio_ccw_private *private =
container_of(vdev, struct vfio_ccw_private, vdev); container_of(vdev, struct vfio_ccw_private, vdev);
unsigned long events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
int ret; int ret;
private->nb.notifier_call = vfio_ccw_mdev_notifier; /* Device cannot simply be opened again from this state */
if (private->state == VFIO_CCW_STATE_NOT_OPER)
ret = vfio_register_notifier(vdev, VFIO_IOMMU_NOTIFY, return -EINVAL;
&events, &private->nb);
if (ret)
return ret;
ret = vfio_ccw_register_async_dev_regions(private); ret = vfio_ccw_register_async_dev_regions(private);
if (ret) if (ret)
goto out_unregister; return ret;
ret = vfio_ccw_register_schib_dev_regions(private); ret = vfio_ccw_register_schib_dev_regions(private);
if (ret) if (ret)
...@@ -200,11 +156,16 @@ static int vfio_ccw_mdev_open_device(struct vfio_device *vdev) ...@@ -200,11 +156,16 @@ static int vfio_ccw_mdev_open_device(struct vfio_device *vdev)
if (ret) if (ret)
goto out_unregister; goto out_unregister;
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_OPEN);
if (private->state == VFIO_CCW_STATE_NOT_OPER) {
ret = -EINVAL;
goto out_unregister;
}
return ret; return ret;
out_unregister: out_unregister:
vfio_ccw_unregister_dev_regions(private); vfio_ccw_unregister_dev_regions(private);
vfio_unregister_notifier(vdev, VFIO_IOMMU_NOTIFY, &private->nb);
return ret; return ret;
} }
...@@ -213,16 +174,8 @@ static void vfio_ccw_mdev_close_device(struct vfio_device *vdev) ...@@ -213,16 +174,8 @@ static void vfio_ccw_mdev_close_device(struct vfio_device *vdev)
struct vfio_ccw_private *private = struct vfio_ccw_private *private =
container_of(vdev, struct vfio_ccw_private, vdev); container_of(vdev, struct vfio_ccw_private, vdev);
if ((private->state != VFIO_CCW_STATE_NOT_OPER) && vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_CLOSE);
(private->state != VFIO_CCW_STATE_STANDBY)) {
if (!vfio_ccw_mdev_reset(private))
private->state = VFIO_CCW_STATE_STANDBY;
/* The state will be NOT_OPER on error. */
}
cp_free(&private->cp);
vfio_ccw_unregister_dev_regions(private); 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, static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private,
...@@ -645,6 +598,7 @@ static const struct vfio_device_ops vfio_ccw_dev_ops = { ...@@ -645,6 +598,7 @@ static const struct vfio_device_ops vfio_ccw_dev_ops = {
.write = vfio_ccw_mdev_write, .write = vfio_ccw_mdev_write,
.ioctl = vfio_ccw_mdev_ioctl, .ioctl = vfio_ccw_mdev_ioctl,
.request = vfio_ccw_mdev_request, .request = vfio_ccw_mdev_request,
.dma_unmap = vfio_ccw_dma_unmap,
}; };
struct mdev_driver vfio_ccw_mdev_driver = { struct mdev_driver vfio_ccw_mdev_driver = {
...@@ -657,13 +611,3 @@ struct mdev_driver vfio_ccw_mdev_driver = { ...@@ -657,13 +611,3 @@ struct mdev_driver vfio_ccw_mdev_driver = {
.remove = vfio_ccw_mdev_remove, .remove = vfio_ccw_mdev_remove,
.supported_type_groups = mdev_type_groups, .supported_type_groups = mdev_type_groups,
}; };
int vfio_ccw_mdev_reg(struct subchannel *sch)
{
return mdev_register_device(&sch->dev, &vfio_ccw_mdev_driver);
}
void vfio_ccw_mdev_unreg(struct subchannel *sch)
{
mdev_unregister_device(&sch->dev);
}
...@@ -73,8 +73,6 @@ struct vfio_ccw_crw { ...@@ -73,8 +73,6 @@ struct vfio_ccw_crw {
* @state: internal state of the device * @state: internal state of the device
* @completion: synchronization helper of the I/O completion * @completion: synchronization helper of the I/O completion
* @avail: available for creating a mediated device * @avail: available for creating a mediated device
* @mdev: pointer to the mediated device
* @nb: notifier for vfio events
* @io_region: MMIO region to input/output I/O arguments/results * @io_region: MMIO region to input/output I/O arguments/results
* @io_mutex: protect against concurrent update of I/O regions * @io_mutex: protect against concurrent update of I/O regions
* @region: additional regions for other subchannel operations * @region: additional regions for other subchannel operations
...@@ -97,8 +95,6 @@ struct vfio_ccw_private { ...@@ -97,8 +95,6 @@ struct vfio_ccw_private {
int state; int state;
struct completion *completion; struct completion *completion;
atomic_t avail; atomic_t avail;
struct mdev_device *mdev;
struct notifier_block nb;
struct ccw_io_region *io_region; struct ccw_io_region *io_region;
struct mutex io_mutex; struct mutex io_mutex;
struct vfio_ccw_region *region; struct vfio_ccw_region *region;
...@@ -119,10 +115,7 @@ struct vfio_ccw_private { ...@@ -119,10 +115,7 @@ struct vfio_ccw_private {
struct work_struct crw_work; struct work_struct crw_work;
} __aligned(8); } __aligned(8);
extern int vfio_ccw_mdev_reg(struct subchannel *sch); int vfio_ccw_sch_quiesce(struct subchannel *sch);
extern void vfio_ccw_mdev_unreg(struct subchannel *sch);
extern int vfio_ccw_sch_quiesce(struct subchannel *sch);
extern struct mdev_driver vfio_ccw_mdev_driver; extern struct mdev_driver vfio_ccw_mdev_driver;
...@@ -147,6 +140,8 @@ enum vfio_ccw_event { ...@@ -147,6 +140,8 @@ enum vfio_ccw_event {
VFIO_CCW_EVENT_IO_REQ, VFIO_CCW_EVENT_IO_REQ,
VFIO_CCW_EVENT_INTERRUPT, VFIO_CCW_EVENT_INTERRUPT,
VFIO_CCW_EVENT_ASYNC_REQ, VFIO_CCW_EVENT_ASYNC_REQ,
VFIO_CCW_EVENT_OPEN,
VFIO_CCW_EVENT_CLOSE,
/* last element! */ /* last element! */
NR_VFIO_CCW_EVENTS NR_VFIO_CCW_EVENTS
}; };
...@@ -158,7 +153,7 @@ typedef void (fsm_func_t)(struct vfio_ccw_private *, enum vfio_ccw_event); ...@@ -158,7 +153,7 @@ typedef void (fsm_func_t)(struct vfio_ccw_private *, enum vfio_ccw_event);
extern fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS]; extern fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS];
static inline void vfio_ccw_fsm_event(struct vfio_ccw_private *private, static inline void vfio_ccw_fsm_event(struct vfio_ccw_private *private,
int event) enum vfio_ccw_event event)
{ {
trace_vfio_ccw_fsm_event(private->sch->schid, private->state, event); trace_vfio_ccw_fsm_event(private->sch->schid, private->state, event);
vfio_ccw_jumptable[private->state][event](private, event); vfio_ccw_jumptable[private->state][event](private, event);
......
...@@ -34,7 +34,7 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) ...@@ -34,7 +34,7 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind)
qirqctrl.ir = 1; qirqctrl.ir = 1;
qirqctrl.isc = AP_ISC; qirqctrl.isc = AP_ISC;
status = ap_aqic(aq->qid, qirqctrl, ind); status = ap_aqic(aq->qid, qirqctrl, virt_to_phys(ind));
switch (status.response_code) { switch (status.response_code) {
case AP_RESPONSE_NORMAL: case AP_RESPONSE_NORMAL:
case AP_RESPONSE_OTHERWISE_CHANGED: case AP_RESPONSE_OTHERWISE_CHANGED:
......
...@@ -112,7 +112,7 @@ static void vfio_ap_wait_for_irqclear(int apqn) ...@@ -112,7 +112,7 @@ static void vfio_ap_wait_for_irqclear(int apqn)
* *
* Unregisters the ISC in the GIB when the saved ISC not invalid. * Unregisters the ISC in the GIB when the saved ISC not invalid.
* Unpins the guest's page holding the NIB when it exists. * Unpins the guest's page holding the NIB when it exists.
* Resets the saved_pfn and saved_isc to invalid values. * Resets the saved_iova and saved_isc to invalid values.
*/ */
static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
{ {
...@@ -123,9 +123,9 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) ...@@ -123,9 +123,9 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q)
kvm_s390_gisc_unregister(q->matrix_mdev->kvm, q->saved_isc); kvm_s390_gisc_unregister(q->matrix_mdev->kvm, q->saved_isc);
q->saved_isc = VFIO_AP_ISC_INVALID; q->saved_isc = VFIO_AP_ISC_INVALID;
} }
if (q->saved_pfn && !WARN_ON(!q->matrix_mdev)) { if (q->saved_iova && !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_iova, 1);
q->saved_pfn = 0; q->saved_iova = 0;
} }
} }
...@@ -154,7 +154,7 @@ static struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q) ...@@ -154,7 +154,7 @@ static struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
int retries = 5; int retries = 5;
do { do {
status = ap_aqic(q->apqn, aqic_gisa, NULL); status = ap_aqic(q->apqn, aqic_gisa, 0);
switch (status.response_code) { switch (status.response_code) {
case AP_RESPONSE_OTHERWISE_CHANGED: case AP_RESPONSE_OTHERWISE_CHANGED:
case AP_RESPONSE_NORMAL: case AP_RESPONSE_NORMAL:
...@@ -189,27 +189,19 @@ static struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q) ...@@ -189,27 +189,19 @@ static struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q)
* *
* @vcpu: the object representing the vcpu executing the PQAP(AQIC) instruction. * @vcpu: the object representing the vcpu executing the PQAP(AQIC) instruction.
* @nib: the location for storing the nib address. * @nib: the location for storing the nib address.
* @g_pfn: the location for storing the page frame number of the page containing
* the nib.
* *
* When the PQAP(AQIC) instruction is executed, general register 2 contains the * When the PQAP(AQIC) instruction is executed, general register 2 contains the
* address of the notification indicator byte (nib) used for IRQ notification. * address of the notification indicator byte (nib) used for IRQ notification.
* This function parses the nib from gr2 and calculates the page frame * This function parses and validates the nib from gr2.
* number for the guest of the page containing the nib. The values are
* stored in @nib and @g_pfn respectively.
*
* The g_pfn of the nib is then validated to ensure the nib address is valid.
* *
* Return: returns zero if the nib address is a valid; otherwise, returns * Return: returns zero if the nib address is a valid; otherwise, returns
* -EINVAL. * -EINVAL.
*/ */
static int vfio_ap_validate_nib(struct kvm_vcpu *vcpu, unsigned long *nib, static int vfio_ap_validate_nib(struct kvm_vcpu *vcpu, dma_addr_t *nib)
unsigned long *g_pfn)
{ {
*nib = vcpu->run->s.regs.gprs[2]; *nib = vcpu->run->s.regs.gprs[2];
*g_pfn = *nib >> PAGE_SHIFT;
if (kvm_is_error_hva(gfn_to_hva(vcpu->kvm, *g_pfn))) if (kvm_is_error_hva(gfn_to_hva(vcpu->kvm, *nib >> PAGE_SHIFT)))
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -239,33 +231,34 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, ...@@ -239,33 +231,34 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
int isc, int isc,
struct kvm_vcpu *vcpu) struct kvm_vcpu *vcpu)
{ {
unsigned long nib;
struct ap_qirq_ctrl aqic_gisa = {}; struct ap_qirq_ctrl aqic_gisa = {};
struct ap_queue_status status = {}; struct ap_queue_status status = {};
struct kvm_s390_gisa *gisa; struct kvm_s390_gisa *gisa;
struct page *h_page;
int nisc; int nisc;
struct kvm *kvm; struct kvm *kvm;
unsigned long h_nib, g_pfn, h_pfn; phys_addr_t h_nib;
dma_addr_t nib;
int ret; int ret;
/* Verify that the notification indicator byte address is valid */ /* Verify that the notification indicator byte address is valid */
if (vfio_ap_validate_nib(vcpu, &nib, &g_pfn)) { if (vfio_ap_validate_nib(vcpu, &nib)) {
VFIO_AP_DBF_WARN("%s: invalid NIB address: nib=%#lx, g_pfn=%#lx, apqn=%#04x\n", VFIO_AP_DBF_WARN("%s: invalid NIB address: nib=%pad, apqn=%#04x\n",
__func__, nib, g_pfn, q->apqn); __func__, &nib, q->apqn);
status.response_code = AP_RESPONSE_INVALID_ADDRESS; status.response_code = AP_RESPONSE_INVALID_ADDRESS;
return status; return status;
} }
ret = vfio_pin_pages(&q->matrix_mdev->vdev, &g_pfn, 1, ret = vfio_pin_pages(&q->matrix_mdev->vdev, nib, 1,
IOMMU_READ | IOMMU_WRITE, &h_pfn); IOMMU_READ | IOMMU_WRITE, &h_page);
switch (ret) { switch (ret) {
case 1: case 1:
break; break;
default: default:
VFIO_AP_DBF_WARN("%s: vfio_pin_pages failed: rc=%d," VFIO_AP_DBF_WARN("%s: vfio_pin_pages failed: rc=%d,"
"nib=%#lx, g_pfn=%#lx, apqn=%#04x\n", "nib=%pad, apqn=%#04x\n",
__func__, ret, nib, g_pfn, q->apqn); __func__, ret, &nib, q->apqn);
status.response_code = AP_RESPONSE_INVALID_ADDRESS; status.response_code = AP_RESPONSE_INVALID_ADDRESS;
return status; return status;
...@@ -274,7 +267,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, ...@@ -274,7 +267,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
kvm = q->matrix_mdev->kvm; kvm = q->matrix_mdev->kvm;
gisa = kvm->arch.gisa_int.origin; gisa = kvm->arch.gisa_int.origin;
h_nib = (h_pfn << PAGE_SHIFT) | (nib & ~PAGE_MASK); h_nib = page_to_phys(h_page) | (nib & ~PAGE_MASK);
aqic_gisa.gisc = isc; aqic_gisa.gisc = isc;
nisc = kvm_s390_gisc_register(kvm, isc); nisc = kvm_s390_gisc_register(kvm, isc);
...@@ -290,17 +283,17 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, ...@@ -290,17 +283,17 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q,
aqic_gisa.ir = 1; aqic_gisa.ir = 1;
aqic_gisa.gisa = (uint64_t)gisa >> 4; aqic_gisa.gisa = (uint64_t)gisa >> 4;
status = ap_aqic(q->apqn, aqic_gisa, (void *)h_nib); status = ap_aqic(q->apqn, aqic_gisa, h_nib);
switch (status.response_code) { switch (status.response_code) {
case AP_RESPONSE_NORMAL: case AP_RESPONSE_NORMAL:
/* See if we did clear older IRQ configuration */ /* See if we did clear older IRQ configuration */
vfio_ap_free_aqic_resources(q); vfio_ap_free_aqic_resources(q);
q->saved_pfn = g_pfn; q->saved_iova = nib;
q->saved_isc = isc; q->saved_isc = isc;
break; break;
case AP_RESPONSE_OTHERWISE_CHANGED: case AP_RESPONSE_OTHERWISE_CHANGED:
/* We could not modify IRQ setings: clear new configuration */ /* 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, nib, 1);
kvm_s390_gisc_unregister(kvm, isc); kvm_s390_gisc_unregister(kvm, isc);
break; break;
default: default:
...@@ -1226,34 +1219,13 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev, ...@@ -1226,34 +1219,13 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev,
return 0; return 0;
} }
/** static void vfio_ap_mdev_dma_unmap(struct vfio_device *vdev, u64 iova,
* vfio_ap_mdev_iommu_notifier - IOMMU notifier callback u64 length)
*
* @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)
{ {
struct ap_matrix_mdev *matrix_mdev; struct ap_matrix_mdev *matrix_mdev =
container_of(vdev, struct ap_matrix_mdev, vdev);
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;
vfio_unpin_pages(&matrix_mdev->vdev, &g_pfn, 1);
return NOTIFY_OK;
}
return NOTIFY_DONE; vfio_unpin_pages(&matrix_mdev->vdev, iova, 1);
} }
/** /**
...@@ -1380,27 +1352,11 @@ static int vfio_ap_mdev_open_device(struct vfio_device *vdev) ...@@ -1380,27 +1352,11 @@ static int vfio_ap_mdev_open_device(struct vfio_device *vdev)
{ {
struct ap_matrix_mdev *matrix_mdev = struct ap_matrix_mdev *matrix_mdev =
container_of(vdev, struct ap_matrix_mdev, vdev); container_of(vdev, struct ap_matrix_mdev, vdev);
unsigned long events;
int ret;
if (!vdev->kvm) if (!vdev->kvm)
return -EINVAL; return -EINVAL;
ret = vfio_ap_mdev_set_kvm(matrix_mdev, vdev->kvm); return 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;
} }
static void vfio_ap_mdev_close_device(struct vfio_device *vdev) static void vfio_ap_mdev_close_device(struct vfio_device *vdev)
...@@ -1408,8 +1364,6 @@ static void vfio_ap_mdev_close_device(struct vfio_device *vdev) ...@@ -1408,8 +1364,6 @@ static void vfio_ap_mdev_close_device(struct vfio_device *vdev)
struct ap_matrix_mdev *matrix_mdev = struct ap_matrix_mdev *matrix_mdev =
container_of(vdev, struct ap_matrix_mdev, vdev); 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); vfio_ap_mdev_unset_kvm(matrix_mdev);
} }
...@@ -1461,6 +1415,7 @@ static const struct vfio_device_ops vfio_ap_matrix_dev_ops = { ...@@ -1461,6 +1415,7 @@ static const struct vfio_device_ops vfio_ap_matrix_dev_ops = {
.open_device = vfio_ap_mdev_open_device, .open_device = vfio_ap_mdev_open_device,
.close_device = vfio_ap_mdev_close_device, .close_device = vfio_ap_mdev_close_device,
.ioctl = vfio_ap_mdev_ioctl, .ioctl = vfio_ap_mdev_ioctl,
.dma_unmap = vfio_ap_mdev_dma_unmap,
}; };
static struct mdev_driver vfio_ap_matrix_driver = { static struct mdev_driver vfio_ap_matrix_driver = {
......
...@@ -81,8 +81,6 @@ struct ap_matrix { ...@@ -81,8 +81,6 @@ struct ap_matrix {
* @node: allows the ap_matrix_mdev struct to be added to a list * @node: allows the ap_matrix_mdev struct to be added to a list
* @matrix: the adapters, usage domains and control domains assigned to the * @matrix: the adapters, usage domains and control domains assigned to the
* mediated matrix device. * mediated matrix device.
* @iommu_notifier: notifier block used for specifying callback function for
* handling the VFIO_IOMMU_NOTIFY_DMA_UNMAP even
* @kvm: the struct holding guest's state * @kvm: the struct holding guest's state
* @pqap_hook: the function pointer to the interception handler for the * @pqap_hook: the function pointer to the interception handler for the
* PQAP(AQIC) instruction. * PQAP(AQIC) instruction.
...@@ -92,7 +90,6 @@ struct ap_matrix_mdev { ...@@ -92,7 +90,6 @@ struct ap_matrix_mdev {
struct vfio_device vdev; struct vfio_device vdev;
struct list_head node; struct list_head node;
struct ap_matrix matrix; struct ap_matrix matrix;
struct notifier_block iommu_notifier;
struct kvm *kvm; struct kvm *kvm;
crypto_hook pqap_hook; crypto_hook pqap_hook;
struct mdev_device *mdev; struct mdev_device *mdev;
...@@ -102,13 +99,13 @@ struct ap_matrix_mdev { ...@@ -102,13 +99,13 @@ struct ap_matrix_mdev {
* struct vfio_ap_queue - contains the data associated with a queue bound to the * struct vfio_ap_queue - contains the data associated with a queue bound to the
* vfio_ap device driver * vfio_ap device driver
* @matrix_mdev: the matrix mediated device * @matrix_mdev: the matrix mediated device
* @saved_pfn: the guest PFN pinned for the guest * @saved_iova: the notification indicator byte (nib) address
* @apqn: the APQN of the AP queue device * @apqn: the APQN of the AP queue device
* @saved_isc: the guest ISC registered with the GIB interface * @saved_isc: the guest ISC registered with the GIB interface
*/ */
struct vfio_ap_queue { struct vfio_ap_queue {
struct ap_matrix_mdev *matrix_mdev; struct ap_matrix_mdev *matrix_mdev;
unsigned long saved_pfn; dma_addr_t saved_iova;
int apqn; int apqn;
#define VFIO_AP_ISC_INVALID 0xff #define VFIO_AP_ISC_INVALID 0xff
unsigned char saved_isc; unsigned char saved_isc;
......
...@@ -39,7 +39,7 @@ struct vfio_fsl_mc_device { ...@@ -39,7 +39,7 @@ struct vfio_fsl_mc_device {
struct vfio_fsl_mc_irq *mc_irqs; struct vfio_fsl_mc_irq *mc_irqs;
}; };
extern int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev,
u32 flags, unsigned int index, u32 flags, unsigned int index,
unsigned int start, unsigned int count, unsigned int start, unsigned int count,
void *data); void *data);
......
...@@ -1185,7 +1185,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev) ...@@ -1185,7 +1185,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
if (ret) if (ret)
return ret; return ret;
if (core_vdev->ops->migration_set_state) { if (core_vdev->mig_ops) {
ret = hisi_acc_vf_qm_init(hisi_acc_vdev); ret = hisi_acc_vf_qm_init(hisi_acc_vdev);
if (ret) { if (ret) {
vfio_pci_core_disable(vdev); vfio_pci_core_disable(vdev);
...@@ -1208,6 +1208,11 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev) ...@@ -1208,6 +1208,11 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
vfio_pci_core_close_device(core_vdev); vfio_pci_core_close_device(core_vdev);
} }
static const struct vfio_migration_ops hisi_acc_vfio_pci_migrn_state_ops = {
.migration_set_state = hisi_acc_vfio_pci_set_device_state,
.migration_get_state = hisi_acc_vfio_pci_get_device_state,
};
static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = { static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
.name = "hisi-acc-vfio-pci-migration", .name = "hisi-acc-vfio-pci-migration",
.open_device = hisi_acc_vfio_pci_open_device, .open_device = hisi_acc_vfio_pci_open_device,
...@@ -1219,8 +1224,6 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = { ...@@ -1219,8 +1224,6 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
.mmap = hisi_acc_vfio_pci_mmap, .mmap = hisi_acc_vfio_pci_mmap,
.request = vfio_pci_core_request, .request = vfio_pci_core_request,
.match = vfio_pci_core_match, .match = vfio_pci_core_match,
.migration_set_state = hisi_acc_vfio_pci_set_device_state,
.migration_get_state = hisi_acc_vfio_pci_get_device_state,
}; };
static const struct vfio_device_ops hisi_acc_vfio_pci_ops = { static const struct vfio_device_ops hisi_acc_vfio_pci_ops = {
...@@ -1272,6 +1275,8 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device ...@@ -1272,6 +1275,8 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
if (!ret) { if (!ret) {
vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev, vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev,
&hisi_acc_vfio_pci_migrn_ops); &hisi_acc_vfio_pci_migrn_ops);
hisi_acc_vdev->core_device.vdev.mig_ops =
&hisi_acc_vfio_pci_migrn_state_ops;
} else { } else {
pci_warn(pdev, "migration support failed, continue with generic interface\n"); pci_warn(pdev, "migration support failed, continue with generic interface\n");
vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev, vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev,
......
...@@ -88,6 +88,16 @@ static int mlx5fv_vf_event(struct notifier_block *nb, ...@@ -88,6 +88,16 @@ static int mlx5fv_vf_event(struct notifier_block *nb,
return 0; return 0;
} }
void mlx5vf_cmd_close_migratable(struct mlx5vf_pci_core_device *mvdev)
{
if (!mvdev->migrate_cap)
return;
mutex_lock(&mvdev->state_mutex);
mlx5vf_disable_fds(mvdev);
mlx5vf_state_mutex_unlock(mvdev);
}
void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev) void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev)
{ {
if (!mvdev->migrate_cap) if (!mvdev->migrate_cap)
...@@ -98,7 +108,8 @@ void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev) ...@@ -98,7 +108,8 @@ void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev)
destroy_workqueue(mvdev->cb_wq); destroy_workqueue(mvdev->cb_wq);
} }
void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev) void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev,
const struct vfio_migration_ops *mig_ops)
{ {
struct pci_dev *pdev = mvdev->core_device.pdev; struct pci_dev *pdev = mvdev->core_device.pdev;
int ret; int ret;
...@@ -139,6 +150,7 @@ void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev) ...@@ -139,6 +150,7 @@ void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev)
mvdev->core_device.vdev.migration_flags = mvdev->core_device.vdev.migration_flags =
VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_STOP_COPY |
VFIO_MIGRATION_P2P; VFIO_MIGRATION_P2P;
mvdev->core_device.vdev.mig_ops = mig_ops;
end: end:
mlx5_vf_put_core_dev(mvdev->mdev); mlx5_vf_put_core_dev(mvdev->mdev);
......
...@@ -62,8 +62,10 @@ int mlx5vf_cmd_suspend_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod); ...@@ -62,8 +62,10 @@ int mlx5vf_cmd_suspend_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod);
int mlx5vf_cmd_resume_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod); int mlx5vf_cmd_resume_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod);
int mlx5vf_cmd_query_vhca_migration_state(struct mlx5vf_pci_core_device *mvdev, int mlx5vf_cmd_query_vhca_migration_state(struct mlx5vf_pci_core_device *mvdev,
size_t *state_size); size_t *state_size);
void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev); void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev,
const struct vfio_migration_ops *mig_ops);
void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev); void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev);
void mlx5vf_cmd_close_migratable(struct mlx5vf_pci_core_device *mvdev);
int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev, int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev,
struct mlx5_vf_migration_file *migf); struct mlx5_vf_migration_file *migf);
int mlx5vf_cmd_load_vhca_state(struct mlx5vf_pci_core_device *mvdev, int mlx5vf_cmd_load_vhca_state(struct mlx5vf_pci_core_device *mvdev,
......
...@@ -570,10 +570,15 @@ static void mlx5vf_pci_close_device(struct vfio_device *core_vdev) ...@@ -570,10 +570,15 @@ static void mlx5vf_pci_close_device(struct vfio_device *core_vdev)
struct mlx5vf_pci_core_device *mvdev = container_of( struct mlx5vf_pci_core_device *mvdev = container_of(
core_vdev, struct mlx5vf_pci_core_device, core_device.vdev); core_vdev, struct mlx5vf_pci_core_device, core_device.vdev);
mlx5vf_disable_fds(mvdev); mlx5vf_cmd_close_migratable(mvdev);
vfio_pci_core_close_device(core_vdev); vfio_pci_core_close_device(core_vdev);
} }
static const struct vfio_migration_ops mlx5vf_pci_mig_ops = {
.migration_set_state = mlx5vf_pci_set_device_state,
.migration_get_state = mlx5vf_pci_get_device_state,
};
static const struct vfio_device_ops mlx5vf_pci_ops = { static const struct vfio_device_ops mlx5vf_pci_ops = {
.name = "mlx5-vfio-pci", .name = "mlx5-vfio-pci",
.open_device = mlx5vf_pci_open_device, .open_device = mlx5vf_pci_open_device,
...@@ -585,8 +590,6 @@ static const struct vfio_device_ops mlx5vf_pci_ops = { ...@@ -585,8 +590,6 @@ static const struct vfio_device_ops mlx5vf_pci_ops = {
.mmap = vfio_pci_core_mmap, .mmap = vfio_pci_core_mmap,
.request = vfio_pci_core_request, .request = vfio_pci_core_request,
.match = vfio_pci_core_match, .match = vfio_pci_core_match,
.migration_set_state = mlx5vf_pci_set_device_state,
.migration_get_state = mlx5vf_pci_get_device_state,
}; };
static int mlx5vf_pci_probe(struct pci_dev *pdev, static int mlx5vf_pci_probe(struct pci_dev *pdev,
...@@ -599,7 +602,7 @@ static int mlx5vf_pci_probe(struct pci_dev *pdev, ...@@ -599,7 +602,7 @@ static int mlx5vf_pci_probe(struct pci_dev *pdev,
if (!mvdev) if (!mvdev)
return -ENOMEM; return -ENOMEM;
vfio_pci_core_init_device(&mvdev->core_device, pdev, &mlx5vf_pci_ops); vfio_pci_core_init_device(&mvdev->core_device, pdev, &mlx5vf_pci_ops);
mlx5vf_cmd_set_migratable(mvdev); mlx5vf_cmd_set_migratable(mvdev, &mlx5vf_pci_mig_ops);
dev_set_drvdata(&pdev->dev, &mvdev->core_device); dev_set_drvdata(&pdev->dev, &mvdev->core_device);
ret = vfio_pci_core_register_device(&mvdev->core_device); ret = vfio_pci_core_register_device(&mvdev->core_device);
if (ret) if (ret)
......
...@@ -222,7 +222,7 @@ static int vfio_default_config_write(struct vfio_pci_core_device *vdev, int pos, ...@@ -222,7 +222,7 @@ static int vfio_default_config_write(struct vfio_pci_core_device *vdev, int pos,
memcpy(vdev->vconfig + pos, &virt_val, count); memcpy(vdev->vconfig + pos, &virt_val, count);
} }
/* Non-virtualzed and writable bits go to hardware */ /* Non-virtualized and writable bits go to hardware */
if (write & ~virt) { if (write & ~virt) {
struct pci_dev *pdev = vdev->pdev; struct pci_dev *pdev = vdev->pdev;
__le32 phys_val = 0; __le32 phys_val = 0;
...@@ -1728,7 +1728,7 @@ int vfio_config_init(struct vfio_pci_core_device *vdev) ...@@ -1728,7 +1728,7 @@ int vfio_config_init(struct vfio_pci_core_device *vdev)
/* /*
* Config space, caps and ecaps are all dword aligned, so we could * Config space, caps and ecaps are all dword aligned, so we could
* use one byte per dword to record the type. However, there are * use one byte per dword to record the type. However, there are
* no requiremenst on the length of a capability, so the gap between * no requirements on the length of a capability, so the gap between
* capabilities needs byte granularity. * capabilities needs byte granularity.
*/ */
map = kmalloc(pdev->cfg_size, GFP_KERNEL); map = kmalloc(pdev->cfg_size, GFP_KERNEL);
......
...@@ -1868,6 +1868,13 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev) ...@@ -1868,6 +1868,13 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev)
if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
return -EINVAL; return -EINVAL;
if (vdev->vdev.mig_ops) {
if (!(vdev->vdev.mig_ops->migration_get_state &&
vdev->vdev.mig_ops->migration_set_state) ||
!(vdev->vdev.migration_flags & VFIO_MIGRATION_STOP_COPY))
return -EINVAL;
}
/* /*
* Prevent binding to PFs with VFs enabled, the VFs might be in use * Prevent binding to PFs with VFs enabled, the VFs might be in use
* by the host or other users. We cannot capture the VFs if they * by the host or other users. We cannot capture the VFs if they
......
...@@ -78,21 +78,20 @@ struct vfio_platform_reset_node { ...@@ -78,21 +78,20 @@ struct vfio_platform_reset_node {
vfio_platform_reset_fn_t of_reset; vfio_platform_reset_fn_t of_reset;
}; };
extern int vfio_platform_probe_common(struct vfio_platform_device *vdev, int vfio_platform_probe_common(struct vfio_platform_device *vdev,
struct device *dev); struct device *dev);
void vfio_platform_remove_common(struct vfio_platform_device *vdev); void vfio_platform_remove_common(struct vfio_platform_device *vdev);
extern int vfio_platform_irq_init(struct vfio_platform_device *vdev); int vfio_platform_irq_init(struct vfio_platform_device *vdev);
extern void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev); void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev);
extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
uint32_t flags, unsigned index, uint32_t flags, unsigned index,
unsigned start, unsigned count, unsigned start, unsigned count, void *data);
void *data);
extern void __vfio_platform_register_reset(struct vfio_platform_reset_node *n); void __vfio_platform_register_reset(struct vfio_platform_reset_node *n);
extern void vfio_platform_unregister_reset(const char *compat, void vfio_platform_unregister_reset(const char *compat,
vfio_platform_reset_fn_t fn); vfio_platform_reset_fn_t fn);
#define vfio_platform_register_reset(__compat, __reset) \ #define vfio_platform_register_reset(__compat, __reset) \
static struct vfio_platform_reset_node __reset ## _node = { \ static struct vfio_platform_reset_node __reset ## _node = { \
.owner = THIS_MODULE, \ .owner = THIS_MODULE, \
......
This diff is collapsed.
...@@ -50,16 +50,15 @@ struct vfio_iommu_driver_ops { ...@@ -50,16 +50,15 @@ struct vfio_iommu_driver_ops {
struct iommu_group *group); struct iommu_group *group);
int (*pin_pages)(void *iommu_data, int (*pin_pages)(void *iommu_data,
struct iommu_group *group, struct iommu_group *group,
unsigned long *user_pfn, dma_addr_t user_iova,
int npage, int prot, int npage, int prot,
unsigned long *phys_pfn); struct page **pages);
int (*unpin_pages)(void *iommu_data, void (*unpin_pages)(void *iommu_data,
unsigned long *user_pfn, int npage); dma_addr_t user_iova, int npage);
int (*register_notifier)(void *iommu_data, void (*register_device)(void *iommu_data,
unsigned long *events, struct vfio_device *vdev);
struct notifier_block *nb); void (*unregister_device)(void *iommu_data,
int (*unregister_notifier)(void *iommu_data, struct vfio_device *vdev);
struct notifier_block *nb);
int (*dma_rw)(void *iommu_data, dma_addr_t user_iova, int (*dma_rw)(void *iommu_data, dma_addr_t user_iova,
void *data, size_t count, bool write); void *data, size_t count, bool write);
struct iommu_domain *(*group_iommu_domain)(void *iommu_data, struct iommu_domain *(*group_iommu_domain)(void *iommu_data,
......
...@@ -378,8 +378,7 @@ static void tce_iommu_release(void *iommu_data) ...@@ -378,8 +378,7 @@ static void tce_iommu_release(void *iommu_data)
kfree(container); kfree(container);
} }
static void tce_iommu_unuse_page(struct tce_container *container, static void tce_iommu_unuse_page(unsigned long hpa)
unsigned long hpa)
{ {
struct page *page; struct page *page;
...@@ -474,7 +473,7 @@ static int tce_iommu_clear(struct tce_container *container, ...@@ -474,7 +473,7 @@ static int tce_iommu_clear(struct tce_container *container,
continue; continue;
} }
tce_iommu_unuse_page(container, oldhpa); tce_iommu_unuse_page(oldhpa);
} }
iommu_tce_kill(tbl, firstentry, pages); iommu_tce_kill(tbl, firstentry, pages);
...@@ -524,7 +523,7 @@ static long tce_iommu_build(struct tce_container *container, ...@@ -524,7 +523,7 @@ static long tce_iommu_build(struct tce_container *container,
ret = iommu_tce_xchg_no_kill(container->mm, tbl, entry + i, ret = iommu_tce_xchg_no_kill(container->mm, tbl, entry + i,
&hpa, &dirtmp); &hpa, &dirtmp);
if (ret) { if (ret) {
tce_iommu_unuse_page(container, hpa); tce_iommu_unuse_page(hpa);
pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%ld\n", pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%ld\n",
__func__, entry << tbl->it_page_shift, __func__, entry << tbl->it_page_shift,
tce, ret); tce, ret);
...@@ -532,7 +531,7 @@ static long tce_iommu_build(struct tce_container *container, ...@@ -532,7 +531,7 @@ static long tce_iommu_build(struct tce_container *container,
} }
if (dirtmp != DMA_NONE) if (dirtmp != DMA_NONE)
tce_iommu_unuse_page(container, hpa); tce_iommu_unuse_page(hpa);
tce += IOMMU_PAGE_SIZE(tbl); tce += IOMMU_PAGE_SIZE(tbl);
} }
...@@ -1266,7 +1265,10 @@ static int tce_iommu_attach_group(void *iommu_data, ...@@ -1266,7 +1265,10 @@ static int tce_iommu_attach_group(void *iommu_data,
goto unlock_exit; goto unlock_exit;
} }
/* Check if new group has the same iommu_ops (i.e. compatible) */ /*
* Check if new group has the same iommu_table_group_ops
* (i.e. compatible)
*/
list_for_each_entry(tcegrp, &container->group_list, next) { list_for_each_entry(tcegrp, &container->group_list, next) {
struct iommu_table_group *table_group_tmp; struct iommu_table_group *table_group_tmp;
......
This diff is collapsed.
...@@ -65,11 +65,6 @@ struct mdev_driver { ...@@ -65,11 +65,6 @@ struct mdev_driver {
struct device_driver driver; struct device_driver driver;
}; };
static inline const guid_t *mdev_uuid(struct mdev_device *mdev)
{
return &mdev->uuid;
}
extern struct bus_type mdev_bus_type; extern struct bus_type mdev_bus_type;
int mdev_register_device(struct device *dev, struct mdev_driver *mdev_driver); int mdev_register_device(struct device *dev, struct mdev_driver *mdev_driver);
......
...@@ -32,6 +32,11 @@ struct vfio_device_set { ...@@ -32,6 +32,11 @@ struct vfio_device_set {
struct vfio_device { struct vfio_device {
struct device *dev; struct device *dev;
const struct vfio_device_ops *ops; const struct vfio_device_ops *ops;
/*
* mig_ops is a static property of the vfio_device which must be set
* prior to registering the vfio_device.
*/
const struct vfio_migration_ops *mig_ops;
struct vfio_group *group; struct vfio_group *group;
struct vfio_device_set *dev_set; struct vfio_device_set *dev_set;
struct list_head dev_set_list; struct list_head dev_set_list;
...@@ -44,6 +49,7 @@ struct vfio_device { ...@@ -44,6 +49,7 @@ struct vfio_device {
unsigned int open_count; unsigned int open_count;
struct completion comp; struct completion comp;
struct list_head group_next; struct list_head group_next;
struct list_head iommu_entry;
}; };
/** /**
...@@ -60,17 +66,9 @@ struct vfio_device { ...@@ -60,17 +66,9 @@ struct vfio_device {
* @match: Optional device name match callback (return: 0 for no-match, >0 for * @match: Optional device name match callback (return: 0 for no-match, >0 for
* match, -errno for abort (ex. match with insufficient or incorrect * match, -errno for abort (ex. match with insufficient or incorrect
* additional args) * additional args)
* @dma_unmap: Called when userspace unmaps IOVA from the container
* this device is attached to.
* @device_feature: Optional, fill in the VFIO_DEVICE_FEATURE ioctl * @device_feature: Optional, fill in the VFIO_DEVICE_FEATURE ioctl
* @migration_set_state: Optional callback to change the migration state for
* devices that support migration. It's mandatory for
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
* The returned FD is used for data transfer according to the FSM
* definition. The driver is responsible to ensure that FD reaches end
* of stream or error whenever the migration FSM leaves a data transfer
* state or before close_device() returns.
* @migration_get_state: Optional callback to get the migration state for
* devices that support migration. It's mandatory for
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
*/ */
struct vfio_device_ops { struct vfio_device_ops {
char *name; char *name;
...@@ -85,8 +83,24 @@ struct vfio_device_ops { ...@@ -85,8 +83,24 @@ struct vfio_device_ops {
int (*mmap)(struct vfio_device *vdev, struct vm_area_struct *vma); int (*mmap)(struct vfio_device *vdev, struct vm_area_struct *vma);
void (*request)(struct vfio_device *vdev, unsigned int count); void (*request)(struct vfio_device *vdev, unsigned int count);
int (*match)(struct vfio_device *vdev, char *buf); int (*match)(struct vfio_device *vdev, char *buf);
void (*dma_unmap)(struct vfio_device *vdev, u64 iova, u64 length);
int (*device_feature)(struct vfio_device *device, u32 flags, int (*device_feature)(struct vfio_device *device, u32 flags,
void __user *arg, size_t argsz); void __user *arg, size_t argsz);
};
/**
* @migration_set_state: Optional callback to change the migration state for
* devices that support migration. It's mandatory for
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
* The returned FD is used for data transfer according to the FSM
* definition. The driver is responsible to ensure that FD reaches end
* of stream or error whenever the migration FSM leaves a data transfer
* state or before close_device() returns.
* @migration_get_state: Optional callback to get the migration state for
* devices that support migration. It's mandatory for
* VFIO_DEVICE_FEATURE_MIGRATION migration support.
*/
struct vfio_migration_ops {
struct file *(*migration_set_state)( struct file *(*migration_set_state)(
struct vfio_device *device, struct vfio_device *device,
enum vfio_device_mig_state new_state); enum vfio_device_mig_state new_state);
...@@ -140,36 +154,18 @@ int vfio_mig_get_next_state(struct vfio_device *device, ...@@ -140,36 +154,18 @@ int vfio_mig_get_next_state(struct vfio_device *device,
/* /*
* External user API * External user API
*/ */
extern struct iommu_group *vfio_file_iommu_group(struct file *file); struct iommu_group *vfio_file_iommu_group(struct file *file);
extern bool vfio_file_enforced_coherent(struct file *file); bool vfio_file_enforced_coherent(struct file *file);
extern void vfio_file_set_kvm(struct file *file, struct kvm *kvm); void vfio_file_set_kvm(struct file *file, struct kvm *kvm);
extern bool vfio_file_has_dev(struct file *file, struct vfio_device *device); bool vfio_file_has_dev(struct file *file, struct vfio_device *device);
#define VFIO_PIN_PAGES_MAX_ENTRIES (PAGE_SIZE/sizeof(unsigned long)) #define VFIO_PIN_PAGES_MAX_ENTRIES (PAGE_SIZE/sizeof(unsigned long))
extern 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); int npage, int prot, struct page **pages);
extern 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);
int npage); int vfio_dma_rw(struct vfio_device *device, dma_addr_t iova,
extern int vfio_dma_rw(struct vfio_device *device, dma_addr_t user_iova, void *data, size_t len, bool write);
void *data, size_t len, bool write);
/* each type has independent events */
enum vfio_notify_type {
VFIO_IOMMU_NOTIFY = 0,
};
/* events for VFIO_IOMMU_NOTIFY */
#define VFIO_IOMMU_NOTIFY_DMA_UNMAP BIT(0)
extern int vfio_register_notifier(struct vfio_device *device,
enum vfio_notify_type type,
unsigned long *required_events,
struct notifier_block *nb);
extern int vfio_unregister_notifier(struct vfio_device *device,
enum vfio_notify_type type,
struct notifier_block *nb);
/* /*
* Sub-module helpers * Sub-module helpers
...@@ -178,25 +174,24 @@ struct vfio_info_cap { ...@@ -178,25 +174,24 @@ struct vfio_info_cap {
struct vfio_info_cap_header *buf; struct vfio_info_cap_header *buf;
size_t size; size_t size;
}; };
extern struct vfio_info_cap_header *vfio_info_cap_add( struct vfio_info_cap_header *vfio_info_cap_add(struct vfio_info_cap *caps,
struct vfio_info_cap *caps, size_t size, u16 id, u16 version); size_t size, u16 id,
extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset); u16 version);
void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset);
extern int vfio_info_add_capability(struct vfio_info_cap *caps, int vfio_info_add_capability(struct vfio_info_cap *caps,
struct vfio_info_cap_header *cap, struct vfio_info_cap_header *cap, size_t size);
size_t size);
extern int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr,
int num_irqs, int max_irq_type, int num_irqs, int max_irq_type,
size_t *data_size); size_t *data_size);
struct pci_dev; struct pci_dev;
#if IS_ENABLED(CONFIG_VFIO_SPAPR_EEH) #if IS_ENABLED(CONFIG_VFIO_SPAPR_EEH)
extern void vfio_spapr_pci_eeh_open(struct pci_dev *pdev); void vfio_spapr_pci_eeh_open(struct pci_dev *pdev);
extern void vfio_spapr_pci_eeh_release(struct pci_dev *pdev); void vfio_spapr_pci_eeh_release(struct pci_dev *pdev);
extern long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group, long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group, unsigned int cmd,
unsigned int cmd, unsigned long arg);
unsigned long arg);
#else #else
static inline void vfio_spapr_pci_eeh_open(struct pci_dev *pdev) static inline void vfio_spapr_pci_eeh_open(struct pci_dev *pdev)
{ {
...@@ -230,10 +225,9 @@ struct virqfd { ...@@ -230,10 +225,9 @@ struct virqfd {
struct virqfd **pvirqfd; struct virqfd **pvirqfd;
}; };
extern int vfio_virqfd_enable(void *opaque, int vfio_virqfd_enable(void *opaque, int (*handler)(void *, void *),
int (*handler)(void *, void *), void (*thread)(void *, void *), void *data,
void (*thread)(void *, void *), struct virqfd **pvirqfd, int fd);
void *data, struct virqfd **pvirqfd, int fd); void vfio_virqfd_disable(struct virqfd **pvirqfd);
extern void vfio_virqfd_disable(struct virqfd **pvirqfd);
#endif /* VFIO_H */ #endif /* VFIO_H */
...@@ -147,23 +147,23 @@ struct vfio_pci_core_device { ...@@ -147,23 +147,23 @@ struct vfio_pci_core_device {
#define is_irq_none(vdev) (!(is_intx(vdev) || is_msi(vdev) || is_msix(vdev))) #define is_irq_none(vdev) (!(is_intx(vdev) || is_msi(vdev) || is_msix(vdev)))
#define irq_is(vdev, type) (vdev->irq_type == type) #define irq_is(vdev, type) (vdev->irq_type == type)
extern void vfio_pci_intx_mask(struct vfio_pci_core_device *vdev); void vfio_pci_intx_mask(struct vfio_pci_core_device *vdev);
extern void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev); void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev);
extern int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev, int vfio_pci_set_irqs_ioctl(struct vfio_pci_core_device *vdev,
uint32_t flags, unsigned index, uint32_t flags, unsigned index,
unsigned start, unsigned count, void *data); unsigned start, unsigned count, void *data);
extern ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev,
char __user *buf, size_t count, char __user *buf, size_t count,
loff_t *ppos, bool iswrite); loff_t *ppos, bool iswrite);
extern ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite); size_t count, loff_t *ppos, bool iswrite);
#ifdef CONFIG_VFIO_PCI_VGA #ifdef CONFIG_VFIO_PCI_VGA
extern ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf, ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite); size_t count, loff_t *ppos, bool iswrite);
#else #else
static inline ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, static inline ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev,
char __user *buf, size_t count, char __user *buf, size_t count,
...@@ -173,32 +173,31 @@ static inline ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, ...@@ -173,32 +173,31 @@ static inline ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev,
} }
#endif #endif
extern long vfio_pci_ioeventfd(struct vfio_pci_core_device *vdev, loff_t offset, long vfio_pci_ioeventfd(struct vfio_pci_core_device *vdev, loff_t offset,
uint64_t data, int count, int fd); uint64_t data, int count, int fd);
extern int vfio_pci_init_perm_bits(void); int vfio_pci_init_perm_bits(void);
extern void vfio_pci_uninit_perm_bits(void); void vfio_pci_uninit_perm_bits(void);
extern int vfio_config_init(struct vfio_pci_core_device *vdev); int vfio_config_init(struct vfio_pci_core_device *vdev);
extern void vfio_config_free(struct vfio_pci_core_device *vdev); void vfio_config_free(struct vfio_pci_core_device *vdev);
extern int vfio_pci_register_dev_region(struct vfio_pci_core_device *vdev, int vfio_pci_register_dev_region(struct vfio_pci_core_device *vdev,
unsigned int type, unsigned int subtype, unsigned int type, unsigned int subtype,
const struct vfio_pci_regops *ops, const struct vfio_pci_regops *ops,
size_t size, u32 flags, void *data); size_t size, u32 flags, void *data);
extern int vfio_pci_set_power_state(struct vfio_pci_core_device *vdev, int vfio_pci_set_power_state(struct vfio_pci_core_device *vdev,
pci_power_t state); pci_power_t state);
extern bool __vfio_pci_memory_enabled(struct vfio_pci_core_device *vdev); bool __vfio_pci_memory_enabled(struct vfio_pci_core_device *vdev);
extern void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev);
*vdev); u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev);
extern u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev); void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev,
extern void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev, u16 cmd);
u16 cmd);
#ifdef CONFIG_VFIO_PCI_IGD #ifdef CONFIG_VFIO_PCI_IGD
extern int vfio_pci_igd_init(struct vfio_pci_core_device *vdev); int vfio_pci_igd_init(struct vfio_pci_core_device *vdev);
#else #else
static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev) static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev)
{ {
...@@ -207,8 +206,8 @@ static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev) ...@@ -207,8 +206,8 @@ static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev)
#endif #endif
#ifdef CONFIG_VFIO_PCI_ZDEV_KVM #ifdef CONFIG_VFIO_PCI_ZDEV_KVM
extern int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,
struct vfio_info_cap *caps); struct vfio_info_cap *caps);
int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev); int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev);
void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev); void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev);
#else #else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment