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.crac...@oss.nxp.com>
---
 drivers/vfio/fsl-mc/vfio_fsl_mc.c         | 92 +++++++++++++++++++++--
 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h |  7 +-
 2 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c 
b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index 7ceadb801082..548fb4d80f3f 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -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);
 }
@@ -342,14 +414,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:
@@ -366,7 +442,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);
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h 
b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h
index be60f41af30f..d47ef6215429 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;
@@ -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 */
-- 
2.17.1

Reply via email to