summaryrefslogtreecommitdiff
path: root/drivers/s390/cio/vfio_ccw_ops.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-11-03 13:29:36 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-11-03 13:29:36 -0700
commitd4ec3d5535c784c3adbc41c2bbc5d17a00a4a898 (patch)
tree4b752170355f1d02992d2b266cc22a1ffd98ab34 /drivers/s390/cio/vfio_ccw_ops.c
parenta602285ac11b019e9ce7c3907328e9f95f4967f0 (diff)
parent3bf1311f351ef289f2aee79b86bcece2039fa611 (diff)
downloadlinux-d4ec3d5535c784c3adbc41c2bbc5d17a00a4a898.tar.gz
linux-d4ec3d5535c784c3adbc41c2bbc5d17a00a4a898.tar.bz2
linux-d4ec3d5535c784c3adbc41c2bbc5d17a00a4a898.zip
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 ...
Diffstat (limited to 'drivers/s390/cio/vfio_ccw_ops.c')
-rw-r--r--drivers/s390/cio/vfio_ccw_ops.c142
1 files changed, 80 insertions, 62 deletions
diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c
index 7f540ad0b568..d8589afac272 100644
--- a/drivers/s390/cio/vfio_ccw_ops.c
+++ b/drivers/s390/cio/vfio_ccw_ops.c
@@ -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)