| From 9ea8e954812efc4fc9b27e553019295d4dcd0407 Mon Sep 17 00:00:00 2001 |
| From: Diana Craciun <diana.craciun@nxp.com> |
| Date: Tue, 15 Oct 2019 11:22:26 +0300 |
| Subject: [PATCH] vfio/fsl-mc: Added lock support in preparation for interrupt |
| handling |
| |
| All the devices in a DPRC share the same pool of interrupts. |
| Because of this the access to the pool of interrupts must be |
| protected with a lock. Extend the current lock implementation |
| to have a lock per DPRC. |
| |
| Signed-off-by: Diana Craciun <diana.craciun@nxp.com> |
| --- |
| drivers/vfio/fsl-mc/vfio_fsl_mc.c | 90 ++++++++++++++++++++++++++++--- |
| drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 7 ++- |
| 2 files changed, 89 insertions(+), 8 deletions(-) |
| |
| --- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c |
| +++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c |
| @@ -15,6 +15,75 @@ |
| |
| #include "vfio_fsl_mc_private.h" |
| |
| +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); |
| + |
| + 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) |
| { |
| @@ -55,7 +124,7 @@ static int vfio_fsl_mc_open(void *device |
| 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,11 +132,11 @@ static int vfio_fsl_mc_open(void *device |
| } |
| 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; |
| } |
| @@ -76,12 +145,12 @@ static void vfio_fsl_mc_release(void *de |
| { |
| 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); |
| } |
| @@ -180,7 +249,6 @@ static int vfio_fsl_mc_mmap_mmio(struct |
| return -EINVAL; |
| |
| vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
| - |
| vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff; |
| |
| return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, |
| @@ -335,12 +403,18 @@ static int vfio_fsl_mc_probe(struct fsl_ |
| 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) { |
| + vfio_fsl_mc_reflck_put(vdev->reflck); |
| vfio_iommu_group_put(group, dev); |
| return ret; |
| } |
| - mutex_init(&vdev->driver_lock); |
| |
| return ret; |
| } |
| @@ -374,6 +448,8 @@ static int vfio_fsl_mc_remove(struct fsl |
| if (!vdev) |
| return -EINVAL; |
| |
| + vfio_fsl_mc_reflck_put(vdev->reflck); |
| + |
| if (is_fsl_mc_bus_dprc(mc_dev)) |
| vfio_fsl_mc_cleanup_dprc(vdev->mc_dev); |
| |
| --- 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 { |
| int refcnt; |
| u32 num_regions; |
| struct vfio_fsl_mc_region *regions; |
| - struct mutex driver_lock; |
| + struct vfio_fsl_mc_reflck *reflck; |
| }; |
| |
| #endif /* VFIO_PCI_PRIVATE_H */ |