VFIO updates for v5.16-rc1
- Cleanup vfio iommu_group creation (Christoph Hellwig) - Add individual device reset for vfio/fsl-mc (Diana Craciun) - IGD OpRegion 2.0+ support (Colin Xu) - Use modern cdev lifecycle for vfio_group (Jason Gunthorpe) - Use new mdev API in vfio_ccw (Jason Gunthorpe) -----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEEQvbATlQL0amee4qQI5ubbjuwiyIFAmGC6FYbHGFsZXgud2ls bGlhbXNvbkByZWRoYXQuY29tAAoJECObm247sIsiFhIP/25BVx3z3WkZl8e5+dOv lxrDlEwAxTaxCzERbME+C3x1QWXRqnHOA+ImHEwHxt/CVKDClLXkD4dT5vZnhhzY KZIGGz+kQj8dda1Mw2YXN14UzT4b4I400OC26z94nNUZo6v1jvYqnAiPI+hwZyjZ ePKdESmEI9WDL6SNnSqhPwbHRGM4aC5UriJUy2SSN8vYBuhZrVmTa+ntnZl98fQy 0A/3OjdoMDOmPE49TP189qKCMYoEZWOCg2B8n9FME4XG0S+yd3xQyMuFI5SoVBFx qr6uJgTAWI7aNwxfbGXBUfyha3w0VfS+rnvXajupwUDudwiipmW6JIFBTu4uaDOB koa6fRHBxv9hfcM9eZ/T653tTl20C4oJ00/zdIFrIQlyrSGkTN4DIaNxmlvBgFYi UckEYC4yXak5wjXhChx3B+qiEU9gFuUAdN+gWbPZJgcpJmAhjfCjwHnZPI1hHdt2 NbJCBPPxIsN52J1XQ4ohR7M/wGXXH1XR2j8W6JYBWOdz1lS5QxXho6yFOL597H0Q Q/oCcb7paMFiNFhGDKnHPHDInBJcdC+tBTgHkka14+t2X4GkhxATfwgl7YWh9BLr u/KkSJKunTTKrb2lsk1q15mxSkCMtFQUWfaTI2ilrpi4NoEZfG3WcdXw+GJ+6faG u1+lbKvyYjUAH+gDcRAeWlt1 =AsTx -----END PGP SIGNATURE----- Merge tag 'vfio-v5.16-rc1' of git://github.com/awilliam/linux-vfio Pull VFIO updates from Alex Williamson: - Cleanup vfio iommu_group creation (Christoph Hellwig) - Add individual device reset for vfio/fsl-mc (Diana Craciun) - IGD OpRegion 2.0+ support (Colin Xu) - Use modern cdev lifecycle for vfio_group (Jason Gunthorpe) - Use new mdev API in vfio_ccw (Jason Gunthorpe) * tag 'vfio-v5.16-rc1' of git://github.com/awilliam/linux-vfio: (27 commits) vfio/ccw: Convert to use vfio_register_emulated_iommu_dev() vfio/ccw: Pass vfio_ccw_private not mdev_device to various functions vfio/ccw: Use functions for alloc/free of the vfio_ccw_private vfio/ccw: Remove unneeded GFP_DMA vfio: Use cdev_device_add() instead of device_create() vfio: Use a refcount_t instead of a kref in the vfio_group vfio: Don't leak a group reference if the group already exists vfio: Do not open code the group list search in vfio_create_group() vfio: Delete vfio_get/put_group from vfio_iommu_group_notifier() vfio/pci: Add OpRegion 2.0+ Extended VBT support. vfio/iommu_type1: remove IS_IOMMU_CAP_DOMAIN_IN_CONTAINER vfio/iommu_type1: remove the "external" domain vfio/iommu_type1: initialize pgsize_bitmap in ->open vfio/spapr_tce: reject mediated devices vfio: clean up the check for mediated device in vfio_iommu_type1 vfio: remove the unused mdev iommu hook vfio: move the vfio_iommu_driver_ops interface out of <linux/vfio.h> vfio: remove unused method from vfio_iommu_driver_ops vfio: simplify iommu group allocation for mediated devices vfio: remove the iommudata hack for noiommu groups ...
This commit is contained in:
commit
d4ec3d5535
23 changed files with 974 additions and 932 deletions
|
|
@ -137,16 +137,80 @@ static void vfio_ccw_sch_irq(struct subchannel *sch)
|
|||
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_INTERRUPT);
|
||||
}
|
||||
|
||||
static void vfio_ccw_free_regions(struct vfio_ccw_private *private)
|
||||
static struct vfio_ccw_private *vfio_ccw_alloc_private(struct subchannel *sch)
|
||||
{
|
||||
if (private->crw_region)
|
||||
kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
|
||||
if (private->schib_region)
|
||||
kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
|
||||
if (private->cmd_region)
|
||||
kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
|
||||
if (private->io_region)
|
||||
kmem_cache_free(vfio_ccw_io_region, private->io_region);
|
||||
struct vfio_ccw_private *private;
|
||||
|
||||
private = kzalloc(sizeof(*private), GFP_KERNEL);
|
||||
if (!private)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
private->sch = sch;
|
||||
mutex_init(&private->io_mutex);
|
||||
private->state = VFIO_CCW_STATE_NOT_OPER;
|
||||
INIT_LIST_HEAD(&private->crw);
|
||||
INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
|
||||
INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
|
||||
atomic_set(&private->avail, 1);
|
||||
|
||||
private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
|
||||
GFP_KERNEL);
|
||||
if (!private->cp.guest_cp)
|
||||
goto out_free_private;
|
||||
|
||||
private->io_region = kmem_cache_zalloc(vfio_ccw_io_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!private->io_region)
|
||||
goto out_free_cp;
|
||||
|
||||
private->cmd_region = kmem_cache_zalloc(vfio_ccw_cmd_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!private->cmd_region)
|
||||
goto out_free_io;
|
||||
|
||||
private->schib_region = kmem_cache_zalloc(vfio_ccw_schib_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
|
||||
if (!private->schib_region)
|
||||
goto out_free_cmd;
|
||||
|
||||
private->crw_region = kmem_cache_zalloc(vfio_ccw_crw_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
|
||||
if (!private->crw_region)
|
||||
goto out_free_schib;
|
||||
return private;
|
||||
|
||||
out_free_schib:
|
||||
kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
|
||||
out_free_cmd:
|
||||
kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
|
||||
out_free_io:
|
||||
kmem_cache_free(vfio_ccw_io_region, private->io_region);
|
||||
out_free_cp:
|
||||
kfree(private->cp.guest_cp);
|
||||
out_free_private:
|
||||
mutex_destroy(&private->io_mutex);
|
||||
kfree(private);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static void vfio_ccw_free_private(struct vfio_ccw_private *private)
|
||||
{
|
||||
struct vfio_ccw_crw *crw, *temp;
|
||||
|
||||
list_for_each_entry_safe(crw, temp, &private->crw, next) {
|
||||
list_del(&crw->next);
|
||||
kfree(crw);
|
||||
}
|
||||
|
||||
kmem_cache_free(vfio_ccw_crw_region, private->crw_region);
|
||||
kmem_cache_free(vfio_ccw_schib_region, private->schib_region);
|
||||
kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region);
|
||||
kmem_cache_free(vfio_ccw_io_region, private->io_region);
|
||||
kfree(private->cp.guest_cp);
|
||||
mutex_destroy(&private->io_mutex);
|
||||
kfree(private);
|
||||
}
|
||||
|
||||
static int vfio_ccw_sch_probe(struct subchannel *sch)
|
||||
|
|
@ -161,53 +225,19 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
|
||||
if (!private)
|
||||
return -ENOMEM;
|
||||
private = vfio_ccw_alloc_private(sch);
|
||||
if (IS_ERR(private))
|
||||
return PTR_ERR(private);
|
||||
|
||||
private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1),
|
||||
GFP_KERNEL);
|
||||
if (!private->cp.guest_cp)
|
||||
goto out_free;
|
||||
|
||||
private->io_region = kmem_cache_zalloc(vfio_ccw_io_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!private->io_region)
|
||||
goto out_free;
|
||||
|
||||
private->cmd_region = kmem_cache_zalloc(vfio_ccw_cmd_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
if (!private->cmd_region)
|
||||
goto out_free;
|
||||
|
||||
private->schib_region = kmem_cache_zalloc(vfio_ccw_schib_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
|
||||
if (!private->schib_region)
|
||||
goto out_free;
|
||||
|
||||
private->crw_region = kmem_cache_zalloc(vfio_ccw_crw_region,
|
||||
GFP_KERNEL | GFP_DMA);
|
||||
|
||||
if (!private->crw_region)
|
||||
goto out_free;
|
||||
|
||||
private->sch = sch;
|
||||
dev_set_drvdata(&sch->dev, private);
|
||||
mutex_init(&private->io_mutex);
|
||||
|
||||
spin_lock_irq(sch->lock);
|
||||
private->state = VFIO_CCW_STATE_NOT_OPER;
|
||||
sch->isc = VFIO_CCW_ISC;
|
||||
ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
|
||||
spin_unlock_irq(sch->lock);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
|
||||
INIT_LIST_HEAD(&private->crw);
|
||||
INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
|
||||
INIT_WORK(&private->crw_work, vfio_ccw_crw_todo);
|
||||
atomic_set(&private->avail, 1);
|
||||
private->state = VFIO_CCW_STATE_STANDBY;
|
||||
|
||||
ret = vfio_ccw_mdev_reg(sch);
|
||||
|
|
@ -228,31 +258,20 @@ out_disable:
|
|||
cio_disable_subchannel(sch);
|
||||
out_free:
|
||||
dev_set_drvdata(&sch->dev, NULL);
|
||||
vfio_ccw_free_regions(private);
|
||||
kfree(private->cp.guest_cp);
|
||||
kfree(private);
|
||||
vfio_ccw_free_private(private);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vfio_ccw_sch_remove(struct subchannel *sch)
|
||||
{
|
||||
struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
|
||||
struct vfio_ccw_crw *crw, *temp;
|
||||
|
||||
vfio_ccw_sch_quiesce(sch);
|
||||
|
||||
list_for_each_entry_safe(crw, temp, &private->crw, next) {
|
||||
list_del(&crw->next);
|
||||
kfree(crw);
|
||||
}
|
||||
|
||||
vfio_ccw_mdev_unreg(sch);
|
||||
|
||||
dev_set_drvdata(&sch->dev, NULL);
|
||||
|
||||
vfio_ccw_free_regions(private);
|
||||
kfree(private->cp.guest_cp);
|
||||
kfree(private);
|
||||
vfio_ccw_free_private(private);
|
||||
|
||||
VFIO_CCW_MSG_EVENT(4, "unbound from subchannel %x.%x.%04x\n",
|
||||
sch->schid.cssid, sch->schid.ssid,
|
||||
|
|
@ -449,7 +468,7 @@ static int __init vfio_ccw_sch_init(void)
|
|||
vfio_ccw_work_q = create_singlethread_workqueue("vfio-ccw");
|
||||
if (!vfio_ccw_work_q) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
goto out_regions;
|
||||
}
|
||||
|
||||
vfio_ccw_io_region = kmem_cache_create_usercopy("vfio_ccw_io_region",
|
||||
|
|
@ -458,7 +477,7 @@ static int __init vfio_ccw_sch_init(void)
|
|||
sizeof(struct ccw_io_region), NULL);
|
||||
if (!vfio_ccw_io_region) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
goto out_regions;
|
||||
}
|
||||
|
||||
vfio_ccw_cmd_region = kmem_cache_create_usercopy("vfio_ccw_cmd_region",
|
||||
|
|
@ -467,7 +486,7 @@ static int __init vfio_ccw_sch_init(void)
|
|||
sizeof(struct ccw_cmd_region), NULL);
|
||||
if (!vfio_ccw_cmd_region) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
goto out_regions;
|
||||
}
|
||||
|
||||
vfio_ccw_schib_region = kmem_cache_create_usercopy("vfio_ccw_schib_region",
|
||||
|
|
@ -477,7 +496,7 @@ static int __init vfio_ccw_sch_init(void)
|
|||
|
||||
if (!vfio_ccw_schib_region) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
goto out_regions;
|
||||
}
|
||||
|
||||
vfio_ccw_crw_region = kmem_cache_create_usercopy("vfio_ccw_crw_region",
|
||||
|
|
@ -487,19 +506,25 @@ static int __init vfio_ccw_sch_init(void)
|
|||
|
||||
if (!vfio_ccw_crw_region) {
|
||||
ret = -ENOMEM;
|
||||
goto out_err;
|
||||
goto out_regions;
|
||||
}
|
||||
|
||||
ret = mdev_register_driver(&vfio_ccw_mdev_driver);
|
||||
if (ret)
|
||||
goto out_regions;
|
||||
|
||||
isc_register(VFIO_CCW_ISC);
|
||||
ret = css_driver_register(&vfio_ccw_sch_driver);
|
||||
if (ret) {
|
||||
isc_unregister(VFIO_CCW_ISC);
|
||||
goto out_err;
|
||||
goto out_driver;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
out_err:
|
||||
out_driver:
|
||||
mdev_unregister_driver(&vfio_ccw_mdev_driver);
|
||||
out_regions:
|
||||
vfio_ccw_destroy_regions();
|
||||
destroy_workqueue(vfio_ccw_work_q);
|
||||
vfio_ccw_debug_exit();
|
||||
|
|
@ -509,6 +534,7 @@ out_err:
|
|||
static void __exit vfio_ccw_sch_exit(void)
|
||||
{
|
||||
css_driver_unregister(&vfio_ccw_sch_driver);
|
||||
mdev_unregister_driver(&vfio_ccw_mdev_driver);
|
||||
isc_unregister(VFIO_CCW_ISC);
|
||||
vfio_ccw_destroy_regions();
|
||||
destroy_workqueue(vfio_ccw_work_q);
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
|
||||
#include "vfio_ccw_private.h"
|
||||
|
||||
static int vfio_ccw_mdev_reset(struct mdev_device *mdev)
|
||||
static const struct vfio_device_ops vfio_ccw_dev_ops;
|
||||
|
||||
static int vfio_ccw_mdev_reset(struct vfio_ccw_private *private)
|
||||
{
|
||||
struct vfio_ccw_private *private;
|
||||
struct subchannel *sch;
|
||||
int ret;
|
||||
|
||||
private = dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
sch = private->sch;
|
||||
/*
|
||||
* TODO:
|
||||
|
|
@ -61,7 +61,7 @@ static int vfio_ccw_mdev_notifier(struct notifier_block *nb,
|
|||
if (!cp_iova_pinned(&private->cp, unmap->iova))
|
||||
return NOTIFY_OK;
|
||||
|
||||
if (vfio_ccw_mdev_reset(private->mdev))
|
||||
if (vfio_ccw_mdev_reset(private))
|
||||
return NOTIFY_BAD;
|
||||
|
||||
cp_free(&private->cp);
|
||||
|
|
@ -113,10 +113,10 @@ static struct attribute_group *mdev_type_groups[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static int vfio_ccw_mdev_create(struct mdev_device *mdev)
|
||||
static int vfio_ccw_mdev_probe(struct mdev_device *mdev)
|
||||
{
|
||||
struct vfio_ccw_private *private =
|
||||
dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent);
|
||||
int ret;
|
||||
|
||||
if (private->state == VFIO_CCW_STATE_NOT_OPER)
|
||||
return -ENODEV;
|
||||
|
|
@ -124,6 +124,10 @@ static int vfio_ccw_mdev_create(struct mdev_device *mdev)
|
|||
if (atomic_dec_if_positive(&private->avail) < 0)
|
||||
return -EPERM;
|
||||
|
||||
memset(&private->vdev, 0, sizeof(private->vdev));
|
||||
vfio_init_group_dev(&private->vdev, &mdev->dev,
|
||||
&vfio_ccw_dev_ops);
|
||||
|
||||
private->mdev = mdev;
|
||||
private->state = VFIO_CCW_STATE_IDLE;
|
||||
|
||||
|
|
@ -132,19 +136,31 @@ static int vfio_ccw_mdev_create(struct mdev_device *mdev)
|
|||
private->sch->schid.ssid,
|
||||
private->sch->schid.sch_no);
|
||||
|
||||
ret = vfio_register_emulated_iommu_dev(&private->vdev);
|
||||
if (ret)
|
||||
goto err_atomic;
|
||||
dev_set_drvdata(&mdev->dev, private);
|
||||
return 0;
|
||||
|
||||
err_atomic:
|
||||
vfio_uninit_group_dev(&private->vdev);
|
||||
atomic_inc(&private->avail);
|
||||
private->mdev = NULL;
|
||||
private->state = VFIO_CCW_STATE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vfio_ccw_mdev_remove(struct mdev_device *mdev)
|
||||
static void vfio_ccw_mdev_remove(struct mdev_device *mdev)
|
||||
{
|
||||
struct vfio_ccw_private *private =
|
||||
dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent);
|
||||
|
||||
VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: remove\n",
|
||||
mdev_uuid(mdev), private->sch->schid.cssid,
|
||||
private->sch->schid.ssid,
|
||||
private->sch->schid.sch_no);
|
||||
|
||||
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))
|
||||
|
|
@ -152,23 +168,22 @@ static int vfio_ccw_mdev_remove(struct mdev_device *mdev)
|
|||
/* The state will be NOT_OPER on error. */
|
||||
}
|
||||
|
||||
vfio_uninit_group_dev(&private->vdev);
|
||||
cp_free(&private->cp);
|
||||
private->mdev = NULL;
|
||||
atomic_inc(&private->avail);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vfio_ccw_mdev_open_device(struct mdev_device *mdev)
|
||||
static int vfio_ccw_mdev_open_device(struct vfio_device *vdev)
|
||||
{
|
||||
struct vfio_ccw_private *private =
|
||||
dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
container_of(vdev, struct vfio_ccw_private, vdev);
|
||||
unsigned long events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
|
||||
int ret;
|
||||
|
||||
private->nb.notifier_call = vfio_ccw_mdev_notifier;
|
||||
|
||||
ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
|
||||
ret = vfio_register_notifier(vdev->dev, VFIO_IOMMU_NOTIFY,
|
||||
&events, &private->nb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -189,27 +204,26 @@ static int vfio_ccw_mdev_open_device(struct mdev_device *mdev)
|
|||
|
||||
out_unregister:
|
||||
vfio_ccw_unregister_dev_regions(private);
|
||||
vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
|
||||
vfio_unregister_notifier(vdev->dev, VFIO_IOMMU_NOTIFY,
|
||||
&private->nb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vfio_ccw_mdev_close_device(struct mdev_device *mdev)
|
||||
static void vfio_ccw_mdev_close_device(struct vfio_device *vdev)
|
||||
{
|
||||
struct vfio_ccw_private *private =
|
||||
dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
container_of(vdev, struct vfio_ccw_private, vdev);
|
||||
|
||||
if ((private->state != VFIO_CCW_STATE_NOT_OPER) &&
|
||||
(private->state != VFIO_CCW_STATE_STANDBY)) {
|
||||
if (!vfio_ccw_mdev_reset(mdev))
|
||||
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_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
|
||||
&private->nb);
|
||||
vfio_unregister_notifier(vdev->dev, VFIO_IOMMU_NOTIFY, &private->nb);
|
||||
}
|
||||
|
||||
static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private,
|
||||
|
|
@ -233,15 +247,14 @@ static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t vfio_ccw_mdev_read(struct mdev_device *mdev,
|
||||
static ssize_t vfio_ccw_mdev_read(struct vfio_device *vdev,
|
||||
char __user *buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct vfio_ccw_private *private =
|
||||
container_of(vdev, struct vfio_ccw_private, vdev);
|
||||
unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos);
|
||||
struct vfio_ccw_private *private;
|
||||
|
||||
private = dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
|
||||
if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions)
|
||||
return -EINVAL;
|
||||
|
|
@ -286,15 +299,14 @@ out_unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev,
|
||||
static ssize_t vfio_ccw_mdev_write(struct vfio_device *vdev,
|
||||
const char __user *buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct vfio_ccw_private *private =
|
||||
container_of(vdev, struct vfio_ccw_private, vdev);
|
||||
unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos);
|
||||
struct vfio_ccw_private *private;
|
||||
|
||||
private = dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
|
||||
if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions)
|
||||
return -EINVAL;
|
||||
|
|
@ -311,12 +323,9 @@ static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info,
|
||||
struct mdev_device *mdev)
|
||||
static int vfio_ccw_mdev_get_device_info(struct vfio_ccw_private *private,
|
||||
struct vfio_device_info *info)
|
||||
{
|
||||
struct vfio_ccw_private *private;
|
||||
|
||||
private = dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
info->flags = VFIO_DEVICE_FLAGS_CCW | VFIO_DEVICE_FLAGS_RESET;
|
||||
info->num_regions = VFIO_CCW_NUM_REGIONS + private->num_regions;
|
||||
info->num_irqs = VFIO_CCW_NUM_IRQS;
|
||||
|
|
@ -324,14 +333,12 @@ static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vfio_ccw_mdev_get_region_info(struct vfio_region_info *info,
|
||||
struct mdev_device *mdev,
|
||||
static int vfio_ccw_mdev_get_region_info(struct vfio_ccw_private *private,
|
||||
struct vfio_region_info *info,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct vfio_ccw_private *private;
|
||||
int i;
|
||||
|
||||
private = dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
switch (info->index) {
|
||||
case VFIO_CCW_CONFIG_REGION_INDEX:
|
||||
info->offset = 0;
|
||||
|
|
@ -406,19 +413,16 @@ static int vfio_ccw_mdev_get_irq_info(struct vfio_irq_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vfio_ccw_mdev_set_irqs(struct mdev_device *mdev,
|
||||
static int vfio_ccw_mdev_set_irqs(struct vfio_ccw_private *private,
|
||||
uint32_t flags,
|
||||
uint32_t index,
|
||||
void __user *data)
|
||||
{
|
||||
struct vfio_ccw_private *private;
|
||||
struct eventfd_ctx **ctx;
|
||||
|
||||
if (!(flags & VFIO_IRQ_SET_ACTION_TRIGGER))
|
||||
return -EINVAL;
|
||||
|
||||
private = dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
|
||||
switch (index) {
|
||||
case VFIO_CCW_IO_IRQ_INDEX:
|
||||
ctx = &private->io_trigger;
|
||||
|
|
@ -520,10 +524,12 @@ void vfio_ccw_unregister_dev_regions(struct vfio_ccw_private *private)
|
|||
private->region = NULL;
|
||||
}
|
||||
|
||||
static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
|
||||
static ssize_t vfio_ccw_mdev_ioctl(struct vfio_device *vdev,
|
||||
unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct vfio_ccw_private *private =
|
||||
container_of(vdev, struct vfio_ccw_private, vdev);
|
||||
int ret = 0;
|
||||
unsigned long minsz;
|
||||
|
||||
|
|
@ -540,7 +546,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
|
|||
if (info.argsz < minsz)
|
||||
return -EINVAL;
|
||||
|
||||
ret = vfio_ccw_mdev_get_device_info(&info, mdev);
|
||||
ret = vfio_ccw_mdev_get_device_info(private, &info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -558,7 +564,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
|
|||
if (info.argsz < minsz)
|
||||
return -EINVAL;
|
||||
|
||||
ret = vfio_ccw_mdev_get_region_info(&info, mdev, arg);
|
||||
ret = vfio_ccw_mdev_get_region_info(private, &info, arg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -603,47 +609,59 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
|
|||
return ret;
|
||||
|
||||
data = (void __user *)(arg + minsz);
|
||||
return vfio_ccw_mdev_set_irqs(mdev, hdr.flags, hdr.index, data);
|
||||
return vfio_ccw_mdev_set_irqs(private, hdr.flags, hdr.index,
|
||||
data);
|
||||
}
|
||||
case VFIO_DEVICE_RESET:
|
||||
return vfio_ccw_mdev_reset(mdev);
|
||||
return vfio_ccw_mdev_reset(private);
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request removal of the device*/
|
||||
static void vfio_ccw_mdev_request(struct mdev_device *mdev, unsigned int count)
|
||||
static void vfio_ccw_mdev_request(struct vfio_device *vdev, unsigned int count)
|
||||
{
|
||||
struct vfio_ccw_private *private = dev_get_drvdata(mdev_parent_dev(mdev));
|
||||
|
||||
if (!private)
|
||||
return;
|
||||
struct vfio_ccw_private *private =
|
||||
container_of(vdev, struct vfio_ccw_private, vdev);
|
||||
struct device *dev = vdev->dev;
|
||||
|
||||
if (private->req_trigger) {
|
||||
if (!(count % 10))
|
||||
dev_notice_ratelimited(mdev_dev(private->mdev),
|
||||
dev_notice_ratelimited(dev,
|
||||
"Relaying device request to user (#%u)\n",
|
||||
count);
|
||||
|
||||
eventfd_signal(private->req_trigger, 1);
|
||||
} else if (count == 0) {
|
||||
dev_notice(mdev_dev(private->mdev),
|
||||
dev_notice(dev,
|
||||
"No device request channel registered, blocked until released by user\n");
|
||||
}
|
||||
}
|
||||
|
||||
static const struct vfio_device_ops vfio_ccw_dev_ops = {
|
||||
.open_device = vfio_ccw_mdev_open_device,
|
||||
.close_device = vfio_ccw_mdev_close_device,
|
||||
.read = vfio_ccw_mdev_read,
|
||||
.write = vfio_ccw_mdev_write,
|
||||
.ioctl = vfio_ccw_mdev_ioctl,
|
||||
.request = vfio_ccw_mdev_request,
|
||||
};
|
||||
|
||||
struct mdev_driver vfio_ccw_mdev_driver = {
|
||||
.driver = {
|
||||
.name = "vfio_ccw_mdev",
|
||||
.owner = THIS_MODULE,
|
||||
.mod_name = KBUILD_MODNAME,
|
||||
},
|
||||
.probe = vfio_ccw_mdev_probe,
|
||||
.remove = vfio_ccw_mdev_remove,
|
||||
};
|
||||
|
||||
static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.device_driver = &vfio_ccw_mdev_driver,
|
||||
.supported_type_groups = mdev_type_groups,
|
||||
.create = vfio_ccw_mdev_create,
|
||||
.remove = vfio_ccw_mdev_remove,
|
||||
.open_device = vfio_ccw_mdev_open_device,
|
||||
.close_device = vfio_ccw_mdev_close_device,
|
||||
.read = vfio_ccw_mdev_read,
|
||||
.write = vfio_ccw_mdev_write,
|
||||
.ioctl = vfio_ccw_mdev_ioctl,
|
||||
.request = vfio_ccw_mdev_request,
|
||||
};
|
||||
|
||||
int vfio_ccw_mdev_reg(struct subchannel *sch)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/eventfd.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/vfio_ccw.h>
|
||||
#include <linux/vfio.h>
|
||||
#include <asm/crw.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
|
|
@ -67,6 +68,7 @@ struct vfio_ccw_crw {
|
|||
|
||||
/**
|
||||
* struct vfio_ccw_private
|
||||
* @vdev: Embedded VFIO device
|
||||
* @sch: pointer to the subchannel
|
||||
* @state: internal state of the device
|
||||
* @completion: synchronization helper of the I/O completion
|
||||
|
|
@ -90,6 +92,7 @@ struct vfio_ccw_crw {
|
|||
* @crw_work: work for deferral process of CRW handling
|
||||
*/
|
||||
struct vfio_ccw_private {
|
||||
struct vfio_device vdev;
|
||||
struct subchannel *sch;
|
||||
int state;
|
||||
struct completion *completion;
|
||||
|
|
@ -121,6 +124,8 @@ 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;
|
||||
|
||||
/*
|
||||
* States of the device statemachine.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ static int vfio_ap_mdev_probe(struct mdev_device *mdev)
|
|||
list_add(&matrix_mdev->node, &matrix_dev->mdev_list);
|
||||
mutex_unlock(&matrix_dev->lock);
|
||||
|
||||
ret = vfio_register_group_dev(&matrix_mdev->vdev);
|
||||
ret = vfio_register_emulated_iommu_dev(&matrix_mdev->vdev);
|
||||
if (ret)
|
||||
goto err_list;
|
||||
dev_set_drvdata(&mdev->dev, matrix_mdev);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue