Merge tag 'ecryptfs-5.13-rc1-updates' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / vfio / fsl-mc / vfio_fsl_mc.c
index f27e251..980e595 100644 (file)
@@ -75,7 +75,8 @@ static int vfio_fsl_mc_reflck_attach(struct vfio_fsl_mc_device *vdev)
                        goto unlock;
                }
 
-               cont_vdev = vfio_device_data(device);
+               cont_vdev =
+                       container_of(device, struct vfio_fsl_mc_device, vdev);
                if (!cont_vdev || !cont_vdev->reflck) {
                        vfio_device_put(device);
                        ret = -ENODEV;
@@ -135,9 +136,10 @@ static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev)
        kfree(vdev->regions);
 }
 
-static int vfio_fsl_mc_open(void *device_data)
+static int vfio_fsl_mc_open(struct vfio_device *core_vdev)
 {
-       struct vfio_fsl_mc_device *vdev = device_data;
+       struct vfio_fsl_mc_device *vdev =
+               container_of(core_vdev, struct vfio_fsl_mc_device, vdev);
        int ret;
 
        if (!try_module_get(THIS_MODULE))
@@ -161,9 +163,10 @@ err_reg_init:
        return ret;
 }
 
-static void vfio_fsl_mc_release(void *device_data)
+static void vfio_fsl_mc_release(struct vfio_device *core_vdev)
 {
-       struct vfio_fsl_mc_device *vdev = device_data;
+       struct vfio_fsl_mc_device *vdev =
+               container_of(core_vdev, struct vfio_fsl_mc_device, vdev);
        int ret;
 
        mutex_lock(&vdev->reflck->lock);
@@ -197,11 +200,12 @@ static void vfio_fsl_mc_release(void *device_data)
        module_put(THIS_MODULE);
 }
 
-static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
-                             unsigned long arg)
+static long vfio_fsl_mc_ioctl(struct vfio_device *core_vdev,
+                             unsigned int cmd, unsigned long arg)
 {
        unsigned long minsz;
-       struct vfio_fsl_mc_device *vdev = device_data;
+       struct vfio_fsl_mc_device *vdev =
+               container_of(core_vdev, struct vfio_fsl_mc_device, vdev);
        struct fsl_mc_device *mc_dev = vdev->mc_dev;
 
        switch (cmd) {
@@ -327,10 +331,11 @@ static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
        }
 }
 
-static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf,
+static ssize_t vfio_fsl_mc_read(struct vfio_device *core_vdev, char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct vfio_fsl_mc_device *vdev = device_data;
+       struct vfio_fsl_mc_device *vdev =
+               container_of(core_vdev, struct vfio_fsl_mc_device, vdev);
        unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
        loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
        struct fsl_mc_device *mc_dev = vdev->mc_dev;
@@ -404,10 +409,12 @@ static int vfio_fsl_mc_send_command(void __iomem *ioaddr, uint64_t *cmd_data)
        return 0;
 }
 
-static ssize_t vfio_fsl_mc_write(void *device_data, const char __user *buf,
-                                size_t count, loff_t *ppos)
+static ssize_t vfio_fsl_mc_write(struct vfio_device *core_vdev,
+                                const char __user *buf, size_t count,
+                                loff_t *ppos)
 {
-       struct vfio_fsl_mc_device *vdev = device_data;
+       struct vfio_fsl_mc_device *vdev =
+               container_of(core_vdev, struct vfio_fsl_mc_device, vdev);
        unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos);
        loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK;
        struct fsl_mc_device *mc_dev = vdev->mc_dev;
@@ -468,9 +475,11 @@ static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region,
                               size, vma->vm_page_prot);
 }
 
-static int vfio_fsl_mc_mmap(void *device_data, struct vm_area_struct *vma)
+static int vfio_fsl_mc_mmap(struct vfio_device *core_vdev,
+                           struct vm_area_struct *vma)
 {
-       struct vfio_fsl_mc_device *vdev = device_data;
+       struct vfio_fsl_mc_device *vdev =
+               container_of(core_vdev, struct vfio_fsl_mc_device, vdev);
        struct fsl_mc_device *mc_dev = vdev->mc_dev;
        unsigned int index;
 
@@ -568,23 +577,39 @@ static int vfio_fsl_mc_init_device(struct vfio_fsl_mc_device *vdev)
                dev_err(&mc_dev->dev, "VFIO_FSL_MC: Failed to setup DPRC (%d)\n", ret);
                goto out_nc_unreg;
        }
+       return 0;
+
+out_nc_unreg:
+       bus_unregister_notifier(&fsl_mc_bus_type, &vdev->nb);
+       return ret;
+}
 
+static int vfio_fsl_mc_scan_container(struct fsl_mc_device *mc_dev)
+{
+       int ret;
+
+       /* non dprc devices do not scan for other devices */
+       if (!is_fsl_mc_bus_dprc(mc_dev))
+               return 0;
        ret = dprc_scan_container(mc_dev, false);
        if (ret) {
-               dev_err(&mc_dev->dev, "VFIO_FSL_MC: Container scanning failed (%d)\n", ret);
-               goto out_dprc_cleanup;
+               dev_err(&mc_dev->dev,
+                       "VFIO_FSL_MC: Container scanning failed (%d)\n", ret);
+               dprc_remove_devices(mc_dev, NULL, 0);
+               return ret;
        }
-
        return 0;
+}
+
+static void vfio_fsl_uninit_device(struct vfio_fsl_mc_device *vdev)
+{
+       struct fsl_mc_device *mc_dev = vdev->mc_dev;
+
+       if (!is_fsl_mc_bus_dprc(mc_dev))
+               return;
 
-out_dprc_cleanup:
-       dprc_remove_devices(mc_dev, NULL, 0);
        dprc_cleanup(mc_dev);
-out_nc_unreg:
        bus_unregister_notifier(&fsl_mc_bus_type, &vdev->nb);
-       vdev->nb.notifier_call = NULL;
-
-       return ret;
 }
 
 static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
@@ -600,36 +625,50 @@ static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
                return -EINVAL;
        }
 
-       vdev = devm_kzalloc(dev, sizeof(*vdev), GFP_KERNEL);
+       vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
        if (!vdev) {
                ret = -ENOMEM;
                goto out_group_put;
        }
 
+       vfio_init_group_dev(&vdev->vdev, dev, &vfio_fsl_mc_ops);
        vdev->mc_dev = mc_dev;
-
-       ret = vfio_add_group_dev(dev, &vfio_fsl_mc_ops, vdev);
-       if (ret) {
-               dev_err(dev, "VFIO_FSL_MC: Failed to add to vfio group\n");
-               goto out_group_put;
-       }
+       mutex_init(&vdev->igate);
 
        ret = vfio_fsl_mc_reflck_attach(vdev);
        if (ret)
-               goto out_group_dev;
+               goto out_kfree;
 
        ret = vfio_fsl_mc_init_device(vdev);
        if (ret)
                goto out_reflck;
 
-       mutex_init(&vdev->igate);
+       ret = vfio_register_group_dev(&vdev->vdev);
+       if (ret) {
+               dev_err(dev, "VFIO_FSL_MC: Failed to add to vfio group\n");
+               goto out_device;
+       }
 
+       /*
+        * This triggers recursion into vfio_fsl_mc_probe() on another device
+        * and the vfio_fsl_mc_reflck_attach() must succeed, which relies on the
+        * vfio_add_group_dev() above. It has no impact on this vdev, so it is
+        * safe to be after the vfio device is made live.
+        */
+       ret = vfio_fsl_mc_scan_container(mc_dev);
+       if (ret)
+               goto out_group_dev;
+       dev_set_drvdata(dev, vdev);
        return 0;
 
+out_group_dev:
+       vfio_unregister_group_dev(&vdev->vdev);
+out_device:
+       vfio_fsl_uninit_device(vdev);
 out_reflck:
        vfio_fsl_mc_reflck_put(vdev->reflck);
-out_group_dev:
-       vfio_del_group_dev(dev);
+out_kfree:
+       kfree(vdev);
 out_group_put:
        vfio_iommu_group_put(group, dev);
        return ret;
@@ -637,25 +676,17 @@ out_group_put:
 
 static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
 {
-       struct vfio_fsl_mc_device *vdev;
        struct device *dev = &mc_dev->dev;
+       struct vfio_fsl_mc_device *vdev = dev_get_drvdata(dev);
 
-       vdev = vfio_del_group_dev(dev);
-       if (!vdev)
-               return -EINVAL;
-
+       vfio_unregister_group_dev(&vdev->vdev);
        mutex_destroy(&vdev->igate);
 
+       dprc_remove_devices(mc_dev, NULL, 0);
+       vfio_fsl_uninit_device(vdev);
        vfio_fsl_mc_reflck_put(vdev->reflck);
 
-       if (is_fsl_mc_bus_dprc(mc_dev)) {
-               dprc_remove_devices(mc_dev, NULL, 0);
-               dprc_cleanup(mc_dev);
-       }
-
-       if (vdev->nb.notifier_call)
-               bus_unregister_notifier(&fsl_mc_bus_type, &vdev->nb);
-
+       kfree(vdev);
        vfio_iommu_group_put(mc_dev->dev.iommu_group, dev);
 
        return 0;