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

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
  ...
parents a602285a 3bf1311f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -15,7 +15,8 @@ mc-bus-driver-objs := fsl-mc-bus.o \
		      dprc-driver.o \
		      fsl-mc-allocator.o \
		      fsl-mc-msi.o \
		      dpmcp.o
		      dpmcp.o \
		      obj-api.o

# MC userspace support
obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o
+35 −4
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ struct dpmng_rsp_get_version {

/* DPMCP command IDs */
#define DPMCP_CMDID_CLOSE		DPMCP_CMD(0x800)
#define DPMCP_CMDID_OPEN		DPMCP_CMD(0x80b)
#define DPMCP_CMDID_RESET		DPMCP_CMD(0x005)

struct dpmcp_cmd_open {
@@ -91,7 +90,6 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,

/* DPRC command IDs */
#define DPRC_CMDID_CLOSE                        DPRC_CMD(0x800)
#define DPRC_CMDID_OPEN                         DPRC_CMD(0x805)
#define DPRC_CMDID_GET_API_VERSION              DPRC_CMD(0xa05)

#define DPRC_CMDID_GET_ATTR                     DPRC_CMD(0x004)
@@ -453,7 +451,6 @@ int dprc_get_connection(struct fsl_mc_io *mc_io,

/* Command IDs */
#define DPBP_CMDID_CLOSE		DPBP_CMD(0x800)
#define DPBP_CMDID_OPEN			DPBP_CMD(0x804)

#define DPBP_CMDID_ENABLE		DPBP_CMD(0x002)
#define DPBP_CMDID_DISABLE		DPBP_CMD(0x003)
@@ -492,7 +489,6 @@ struct dpbp_rsp_get_attributes {

/* Command IDs */
#define DPCON_CMDID_CLOSE			DPCON_CMD(0x800)
#define DPCON_CMDID_OPEN			DPCON_CMD(0x808)

#define DPCON_CMDID_ENABLE			DPCON_CMD(0x002)
#define DPCON_CMDID_DISABLE			DPCON_CMD(0x003)
@@ -524,6 +520,41 @@ struct dpcon_cmd_set_notification {
	__le64 user_ctx;
};

/*
 * Generic FSL MC API
 */

/* generic command versioning */
#define OBJ_CMD_BASE_VERSION		1
#define OBJ_CMD_ID_OFFSET		4

#define OBJ_CMD(id)	(((id) << OBJ_CMD_ID_OFFSET) | OBJ_CMD_BASE_VERSION)

/* open command codes */
#define DPRTC_CMDID_OPEN		OBJ_CMD(0x810)
#define DPNI_CMDID_OPEN		OBJ_CMD(0x801)
#define DPSW_CMDID_OPEN		OBJ_CMD(0x802)
#define DPIO_CMDID_OPEN		OBJ_CMD(0x803)
#define DPBP_CMDID_OPEN		OBJ_CMD(0x804)
#define DPRC_CMDID_OPEN		OBJ_CMD(0x805)
#define DPDMUX_CMDID_OPEN		OBJ_CMD(0x806)
#define DPCI_CMDID_OPEN		OBJ_CMD(0x807)
#define DPCON_CMDID_OPEN		OBJ_CMD(0x808)
#define DPSECI_CMDID_OPEN		OBJ_CMD(0x809)
#define DPAIOP_CMDID_OPEN		OBJ_CMD(0x80a)
#define DPMCP_CMDID_OPEN		OBJ_CMD(0x80b)
#define DPMAC_CMDID_OPEN		OBJ_CMD(0x80c)
#define DPDCEI_CMDID_OPEN		OBJ_CMD(0x80d)
#define DPDMAI_CMDID_OPEN		OBJ_CMD(0x80e)
#define DPDBG_CMDID_OPEN		OBJ_CMD(0x80f)

/* Generic object command IDs */
#define OBJ_CMDID_CLOSE		OBJ_CMD(0x800)
#define OBJ_CMDID_RESET		OBJ_CMD(0x005)

struct fsl_mc_obj_cmd_open {
	__le32 obj_id;
};

/**
 * struct fsl_mc_resource_pool - Pool of MC resources of a given
+103 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
 * Copyright 2021 NXP
 *
 */
#include <linux/kernel.h>
#include <linux/fsl/mc.h>

#include "fsl-mc-private.h"

static int fsl_mc_get_open_cmd_id(const char *type)
{
	static const struct {
		int cmd_id;
		const char *type;
	} dev_ids[] = {
		{ DPRTC_CMDID_OPEN, "dprtc" },
		{ DPRC_CMDID_OPEN, "dprc" },
		{ DPNI_CMDID_OPEN, "dpni" },
		{ DPIO_CMDID_OPEN, "dpio" },
		{ DPSW_CMDID_OPEN, "dpsw" },
		{ DPBP_CMDID_OPEN, "dpbp" },
		{ DPCON_CMDID_OPEN, "dpcon" },
		{ DPMCP_CMDID_OPEN, "dpmcp" },
		{ DPMAC_CMDID_OPEN, "dpmac" },
		{ DPSECI_CMDID_OPEN, "dpseci" },
		{ DPDMUX_CMDID_OPEN, "dpdmux" },
		{ DPDCEI_CMDID_OPEN, "dpdcei" },
		{ DPAIOP_CMDID_OPEN, "dpaiop" },
		{ DPCI_CMDID_OPEN, "dpci" },
		{ DPDMAI_CMDID_OPEN, "dpdmai" },
		{ DPDBG_CMDID_OPEN, "dpdbg" },
		{ 0, NULL }
	};
	int i;

	for (i = 0; dev_ids[i].type; i++)
		if (!strcmp(dev_ids[i].type, type))
			return dev_ids[i].cmd_id;

	return -1;
}

int fsl_mc_obj_open(struct fsl_mc_io *mc_io,
		    u32 cmd_flags,
		    int obj_id,
		    char *obj_type,
		    u16 *token)
{
	struct fsl_mc_command cmd = { 0 };
	struct fsl_mc_obj_cmd_open *cmd_params;
	int err = 0;
	int cmd_id = fsl_mc_get_open_cmd_id(obj_type);

	if (cmd_id == -1)
		return -ENODEV;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(cmd_id, cmd_flags, 0);
	cmd_params = (struct fsl_mc_obj_cmd_open *)cmd.params;
	cmd_params->obj_id = cpu_to_le32(obj_id);

	/* send command to mc*/
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	*token = mc_cmd_hdr_read_token(&cmd);

	return err;
}
EXPORT_SYMBOL_GPL(fsl_mc_obj_open);

int fsl_mc_obj_close(struct fsl_mc_io *mc_io,
		     u32 cmd_flags,
		     u16 token)
{
	struct fsl_mc_command cmd = { 0 };

	/* prepare command */
	cmd.header = mc_encode_cmd_header(OBJ_CMDID_CLOSE, cmd_flags,
					  token);

	/* send command to mc*/
	return mc_send_command(mc_io, &cmd);
}
EXPORT_SYMBOL_GPL(fsl_mc_obj_close);

int fsl_mc_obj_reset(struct fsl_mc_io *mc_io,
		     u32 cmd_flags,
		     u16 token)
{
	struct fsl_mc_command cmd = { 0 };

	/* prepare command */
	cmd.header = mc_encode_cmd_header(OBJ_CMDID_RESET, cmd_flags,
					  token);

	/* send command to mc*/
	return mc_send_command(mc_io, &cmd);
}
EXPORT_SYMBOL_GPL(fsl_mc_obj_reset);
+81 −55
Original line number Diff line number Diff line
@@ -137,77 +137,107 @@ 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);
}

static int vfio_ccw_sch_probe(struct subchannel *sch)
{
	struct pmcw *pmcw = &sch->schib.pmcw;
	struct vfio_ccw_private *private;
	int ret = -ENOMEM;

	if (pmcw->qf) {
		dev_warn(&sch->dev, "vfio: ccw: does not support QDIO: %s\n",
			 dev_name(&sch->dev));
		return -ENODEV;
	}

	private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
	private = kzalloc(sizeof(*private), GFP_KERNEL);
	if (!private)
		return -ENOMEM;
		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;
		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;
		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;
		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;
		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;
		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)
{
	struct pmcw *pmcw = &sch->schib.pmcw;
	struct vfio_ccw_private *private;
	int ret = -ENOMEM;

	if (pmcw->qf) {
		dev_warn(&sch->dev, "vfio: ccw: does not support QDIO: %s\n",
			 dev_name(&sch->dev));
		return -ENODEV;
	}

	private = vfio_ccw_alloc_private(sch);
	if (IS_ERR(private))
		return PTR_ERR(private);

	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 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
	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 @@ static int __init vfio_ccw_sch_init(void)
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);
+80 −62
Original line number Diff line number Diff line
@@ -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 @@ static ssize_t vfio_ccw_mdev_write_io_region(struct vfio_ccw_private *private,
	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,41 +609,37 @@ 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 mdev_parent_ops vfio_ccw_mdev_ops = {
	.owner			= THIS_MODULE,
	.supported_type_groups  = mdev_type_groups,
	.create			= vfio_ccw_mdev_create,
	.remove			= vfio_ccw_mdev_remove,
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,
@@ -646,6 +648,22 @@ static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
	.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,
};

int vfio_ccw_mdev_reg(struct subchannel *sch)
{
	return mdev_register_device(&sch->dev, &vfio_ccw_mdev_ops);
Loading