diff mbox series

[v4,06/10] vfio/fsl-mc: Added lock support in preparation for interrupt handling

Message ID 20200826093315.5279-7-diana.craciun@oss.nxp.com (mailing list archive)
State New, archived
Headers show
Series vfio/fsl-mc: VFIO support for FSL-MC device | expand

Commit Message

Diana Madalina Craciun Aug. 26, 2020, 9:33 a.m. UTC
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: Diana Craciun <diana.craciun@oss.nxp.com>
---
 drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 91 +++++++++++++++++++++--
 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  8 +-
 2 files changed, 91 insertions(+), 8 deletions(-)

Comments

Eric Auger Sept. 3, 2020, 7:55 p.m. UTC | #1
Hi Diana

On 8/26/20 11:33 AM, Diana Craciun wrote:
> 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: Diana Craciun <diana.craciun@oss.nxp.com>
> ---
>  drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 91 +++++++++++++++++++++--
>  drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  8 +-
>  2 files changed, 91 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
> index 64d5c1fff51f..bbd3365e877e 100644
> --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
> +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
> @@ -17,6 +17,77 @@
>  
>  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 = 0;
> +
> +	mutex_lock(&reflck_lock);
> +	if (is_fsl_mc_bus_dprc(vdev->mc_dev)) {
> +		vdev->reflck = vfio_fsl_mc_reflck_alloc();
this can fail and if this happens I guess you shouldn't return 0.
> +	} 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);
are we sure cont_mdev always is != NULL?
> +		if (!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;
> @@ -55,7 +126,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)
> @@ -63,12 +134,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;
>  }
> @@ -77,12 +148,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);
>  }
> @@ -329,12 +400,18 @@ static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
>  		return ret;
>  	}
>  
> +	ret = vfio_fsl_mc_reflck_attach(vdev);
> +	if (ret) {
> +		vfio_iommu_group_put(group, dev);
> +		return ret;
> +	}
> +
>  	ret = vfio_fsl_mc_init_device(vdev);
>  	if (ret < 0) {
> +		vfio_fsl_mc_reflck_put(vdev->reflck);
>  		vfio_iommu_group_put(group, dev);
>  		return ret;
>  	}
> -	mutex_init(&vdev->driver_lock);
>  
>  	return ret;
>  }
> @@ -358,7 +435,7 @@ static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
>  
>  	mc_dev->mc_io = NULL;
>  
> -	mutex_destroy(&vdev->driver_lock);
> +	vfio_fsl_mc_reflck_put(vdev->reflck);
>  
>  	vfio_iommu_group_put(mc_dev->dev.iommu_group, dev);
>  
> diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
> index 818dfd3df4db..3b85d930e060 100644
> --- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
> +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
> @@ -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;
> @@ -28,7 +33,8 @@ struct vfio_fsl_mc_device {
>  	int				refcnt;
>  	u32				num_regions;
>  	struct vfio_fsl_mc_region	*regions;
> -	struct mutex driver_lock;
> +	struct vfio_fsl_mc_reflck   *reflck;
> +
>  };
>  
>  #endif /* VFIO_FSL_MC_PRIVATE_H */
> 
Thanks

Eric
diff mbox series

Patch

diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index 64d5c1fff51f..bbd3365e877e 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -17,6 +17,77 @@ 
 
 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 = 0;
+
+	mutex_lock(&reflck_lock);
+	if (is_fsl_mc_bus_dprc(vdev->mc_dev)) {
+		vdev->reflck = vfio_fsl_mc_reflck_alloc();
+	} 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->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;
@@ -55,7 +126,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)
@@ -63,12 +134,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;
 }
@@ -77,12 +148,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);
 }
@@ -329,12 +400,18 @@  static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
 		return ret;
 	}
 
+	ret = vfio_fsl_mc_reflck_attach(vdev);
+	if (ret) {
+		vfio_iommu_group_put(group, dev);
+		return ret;
+	}
+
 	ret = vfio_fsl_mc_init_device(vdev);
 	if (ret < 0) {
+		vfio_fsl_mc_reflck_put(vdev->reflck);
 		vfio_iommu_group_put(group, dev);
 		return ret;
 	}
-	mutex_init(&vdev->driver_lock);
 
 	return ret;
 }
@@ -358,7 +435,7 @@  static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
 
 	mc_dev->mc_io = NULL;
 
-	mutex_destroy(&vdev->driver_lock);
+	vfio_fsl_mc_reflck_put(vdev->reflck);
 
 	vfio_iommu_group_put(mc_dev->dev.iommu_group, dev);
 
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
index 818dfd3df4db..3b85d930e060 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
@@ -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;
@@ -28,7 +33,8 @@  struct vfio_fsl_mc_device {
 	int				refcnt;
 	u32				num_regions;
 	struct vfio_fsl_mc_region	*regions;
-	struct mutex driver_lock;
+	struct vfio_fsl_mc_reflck   *reflck;
+
 };
 
 #endif /* VFIO_FSL_MC_PRIVATE_H */