Commit f2ba7e8c authored by Diana Craciun's avatar Diana Craciun Committed by Alex Williamson
Browse files

vfio/fsl-mc: Added lock support in preparation for interrupt handling



Only the DPRC object allocates interrupts from the MSI
interrupt domain. The interrupts are managed by the DPRC in
a pool of interrupts. The access to this pool of interrupts
has to be protected with a lock.
This patch extends the current lock implementation to have a
lock per DPRC.

Signed-off-by: default avatarDiana Craciun <diana.craciun@oss.nxp.com>
Reviewed-by: default avatarEric Auger <eric.auger@redhat.com>
Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 67247289
Loading
Loading
Loading
Loading
+84 −8
Original line number Diff line number Diff line
@@ -17,6 +17,78 @@

static struct fsl_mc_driver vfio_fsl_mc_driver;

static DEFINE_MUTEX(reflck_lock);

static void vfio_fsl_mc_reflck_get(struct vfio_fsl_mc_reflck *reflck)
{
	kref_get(&reflck->kref);
}

static void vfio_fsl_mc_reflck_release(struct kref *kref)
{
	struct vfio_fsl_mc_reflck *reflck = container_of(kref,
						      struct vfio_fsl_mc_reflck,
						      kref);

	mutex_destroy(&reflck->lock);
	kfree(reflck);
	mutex_unlock(&reflck_lock);
}

static void vfio_fsl_mc_reflck_put(struct vfio_fsl_mc_reflck *reflck)
{
	kref_put_mutex(&reflck->kref, vfio_fsl_mc_reflck_release, &reflck_lock);
}

static struct vfio_fsl_mc_reflck *vfio_fsl_mc_reflck_alloc(void)
{
	struct vfio_fsl_mc_reflck *reflck;

	reflck = kzalloc(sizeof(*reflck), GFP_KERNEL);
	if (!reflck)
		return ERR_PTR(-ENOMEM);

	kref_init(&reflck->kref);
	mutex_init(&reflck->lock);

	return reflck;
}

static int vfio_fsl_mc_reflck_attach(struct vfio_fsl_mc_device *vdev)
{
	int ret;

	mutex_lock(&reflck_lock);
	if (is_fsl_mc_bus_dprc(vdev->mc_dev)) {
		vdev->reflck = vfio_fsl_mc_reflck_alloc();
		ret = PTR_ERR_OR_ZERO(vdev->reflck);
	} else {
		struct device *mc_cont_dev = vdev->mc_dev->dev.parent;
		struct vfio_device *device;
		struct vfio_fsl_mc_device *cont_vdev;

		device = vfio_device_get_from_dev(mc_cont_dev);
		if (!device) {
			ret = -ENODEV;
			goto unlock;
		}

		cont_vdev = vfio_device_data(device);
		if (!cont_vdev || !cont_vdev->reflck) {
			vfio_device_put(device);
			ret = -ENODEV;
			goto unlock;
		}
		vfio_fsl_mc_reflck_get(cont_vdev->reflck);
		vdev->reflck = cont_vdev->reflck;
		vfio_device_put(device);
	}

unlock:
	mutex_unlock(&reflck_lock);
	return ret;
}

static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev)
{
	struct fsl_mc_device *mc_dev = vdev->mc_dev;
@@ -62,7 +134,7 @@ static int vfio_fsl_mc_open(void *device_data)
	if (!try_module_get(THIS_MODULE))
		return -ENODEV;

	mutex_lock(&vdev->driver_lock);
	mutex_lock(&vdev->reflck->lock);
	if (!vdev->refcnt) {
		ret = vfio_fsl_mc_regions_init(vdev);
		if (ret)
@@ -70,12 +142,12 @@ static int vfio_fsl_mc_open(void *device_data)
	}
	vdev->refcnt++;

	mutex_unlock(&vdev->driver_lock);
	mutex_unlock(&vdev->reflck->lock);

	return 0;

err_reg_init:
	mutex_unlock(&vdev->driver_lock);
	mutex_unlock(&vdev->reflck->lock);
	module_put(THIS_MODULE);
	return ret;
}
@@ -84,12 +156,12 @@ static void vfio_fsl_mc_release(void *device_data)
{
	struct vfio_fsl_mc_device *vdev = device_data;

	mutex_lock(&vdev->driver_lock);
	mutex_lock(&vdev->reflck->lock);

	if (!(--vdev->refcnt))
		vfio_fsl_mc_regions_cleanup(vdev);

	mutex_unlock(&vdev->driver_lock);
	mutex_unlock(&vdev->reflck->lock);

	module_put(THIS_MODULE);
}
@@ -343,14 +415,18 @@ static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
		goto out_group_put;
	}

	ret = vfio_fsl_mc_init_device(vdev);
	ret = vfio_fsl_mc_reflck_attach(vdev);
	if (ret)
		goto out_group_dev;

	mutex_init(&vdev->driver_lock);
	ret = vfio_fsl_mc_init_device(vdev);
	if (ret)
		goto out_reflck;

	return 0;

out_reflck:
	vfio_fsl_mc_reflck_put(vdev->reflck);
out_group_dev:
	vfio_del_group_dev(dev);
out_group_put:
@@ -367,7 +443,7 @@ static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
	if (!vdev)
		return -EINVAL;

	mutex_destroy(&vdev->driver_lock);
	vfio_fsl_mc_reflck_put(vdev->reflck);

	if (is_fsl_mc_bus_dprc(mc_dev)) {
		dprc_remove_devices(mc_dev, NULL, 0);
+6 −1
Original line number Diff line number Diff line
@@ -15,6 +15,11 @@
#define VFIO_FSL_MC_INDEX_TO_OFFSET(index)	\
	((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT)

struct vfio_fsl_mc_reflck {
	struct kref		kref;
	struct mutex		lock;
};

struct vfio_fsl_mc_region {
	u32			flags;
	u32			type;
@@ -27,7 +32,7 @@ struct vfio_fsl_mc_device {
	struct notifier_block        nb;
	int				refcnt;
	struct vfio_fsl_mc_region	*regions;
	struct mutex driver_lock;
	struct vfio_fsl_mc_reflck   *reflck;
};

#endif /* VFIO_FSL_MC_PRIVATE_H */