drm: skip redundant minor-lookup in open path
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / gpu / drm / drm_fops.c
index c5b929c..1ec4498 100644 (file)
@@ -44,7 +44,7 @@ DEFINE_MUTEX(drm_global_mutex);
 EXPORT_SYMBOL(drm_global_mutex);
 
 static int drm_open_helper(struct inode *inode, struct file *filp,
-                          struct drm_device * dev);
+                          struct drm_minor *minor);
 
 static int drm_setup(struct drm_device * dev)
 {
@@ -79,38 +79,28 @@ static int drm_setup(struct drm_device * dev)
  */
 int drm_open(struct inode *inode, struct file *filp)
 {
-       struct drm_device *dev = NULL;
-       int minor_id = iminor(inode);
+       struct drm_device *dev;
        struct drm_minor *minor;
-       int retcode = 0;
+       int retcode;
        int need_setup = 0;
-       struct address_space *old_mapping;
-       struct address_space *old_imapping;
-
-       minor = idr_find(&drm_minors_idr, minor_id);
-       if (!minor)
-               return -ENODEV;
 
-       if (!(dev = minor->dev))
-               return -ENODEV;
+       minor = drm_minor_acquire(iminor(inode));
+       if (IS_ERR(minor))
+               return PTR_ERR(minor);
 
-       if (drm_device_is_unplugged(dev))
-               return -ENODEV;
+       dev = minor->dev;
+       if (drm_device_is_unplugged(dev)) {
+               retcode = -ENODEV;
+               goto err_release;
+       }
 
        if (!dev->open_count++)
                need_setup = 1;
-       mutex_lock(&dev->struct_mutex);
-       old_imapping = inode->i_mapping;
-       old_mapping = dev->dev_mapping;
-       if (old_mapping == NULL)
-               dev->dev_mapping = &inode->i_data;
-       /* ihold ensures nobody can remove inode with our i_data */
-       ihold(container_of(dev->dev_mapping, struct inode, i_data));
-       inode->i_mapping = dev->dev_mapping;
-       filp->f_mapping = dev->dev_mapping;
-       mutex_unlock(&dev->struct_mutex);
 
-       retcode = drm_open_helper(inode, filp, dev);
+       /* share address_space across all char-devs of a single device */
+       filp->f_mapping = dev->anon_inode->i_mapping;
+
+       retcode = drm_open_helper(inode, filp, minor);
        if (retcode)
                goto err_undo;
        if (need_setup) {
@@ -121,13 +111,9 @@ int drm_open(struct inode *inode, struct file *filp)
        return 0;
 
 err_undo:
-       mutex_lock(&dev->struct_mutex);
-       filp->f_mapping = old_imapping;
-       inode->i_mapping = old_imapping;
-       iput(container_of(dev->dev_mapping, struct inode, i_data));
-       dev->dev_mapping = old_mapping;
-       mutex_unlock(&dev->struct_mutex);
        dev->open_count--;
+err_release:
+       drm_minor_release(minor);
        return retcode;
 }
 EXPORT_SYMBOL(drm_open);
@@ -143,33 +129,33 @@ EXPORT_SYMBOL(drm_open);
  */
 int drm_stub_open(struct inode *inode, struct file *filp)
 {
-       struct drm_device *dev = NULL;
+       struct drm_device *dev;
        struct drm_minor *minor;
-       int minor_id = iminor(inode);
        int err = -ENODEV;
        const struct file_operations *new_fops;
 
        DRM_DEBUG("\n");
 
        mutex_lock(&drm_global_mutex);
-       minor = idr_find(&drm_minors_idr, minor_id);
-       if (!minor)
-               goto out;
-
-       if (!(dev = minor->dev))
-               goto out;
+       minor = drm_minor_acquire(iminor(inode));
+       if (IS_ERR(minor))
+               goto out_unlock;
 
+       dev = minor->dev;
        if (drm_device_is_unplugged(dev))
-               goto out;
+               goto out_release;
 
        new_fops = fops_get(dev->driver->fops);
        if (!new_fops)
-               goto out;
+               goto out_release;
 
        replace_fops(filp, new_fops);
        if (filp->f_op->open)
                err = filp->f_op->open(inode, filp);
-out:
+
+out_release:
+       drm_minor_release(minor);
+out_unlock:
        mutex_unlock(&drm_global_mutex);
        return err;
 }
@@ -196,16 +182,16 @@ static int drm_cpu_valid(void)
  *
  * \param inode device inode.
  * \param filp file pointer.
- * \param dev device.
+ * \param minor acquired minor-object.
  * \return zero on success or a negative number on failure.
  *
  * Creates and initializes a drm_file structure for the file private data in \p
  * filp and add it into the double linked list in \p dev.
  */
 static int drm_open_helper(struct inode *inode, struct file *filp,
-                          struct drm_device * dev)
+                          struct drm_minor *minor)
 {
-       int minor_id = iminor(inode);
+       struct drm_device *dev = minor->dev;
        struct drm_file *priv;
        int ret;
 
@@ -216,7 +202,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        if (dev->switch_power_state != DRM_SWITCH_POWER_ON && dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF)
                return -EINVAL;
 
-       DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
+       DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index);
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -226,13 +212,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        priv->filp = filp;
        priv->uid = current_euid();
        priv->pid = get_pid(task_pid(current));
-       priv->minor = idr_find(&drm_minors_idr, minor_id);
-       if (!priv->minor) {
-               ret = -ENODEV;
-               goto out_put_pid;
-       }
+       priv->minor = minor;
 
-       priv->ioctl_count = 0;
        /* for compatibility root is always authenticated */
        priv->always_authenticated = capable(CAP_SYS_ADMIN);
        priv->authenticated = priv->always_authenticated;
@@ -337,7 +318,6 @@ out_prime_destroy:
                drm_prime_destroy_file_private(&priv->prime);
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_release(dev, priv);
-out_put_pid:
        put_pid(priv->pid);
        kfree(priv);
        filp->private_data = NULL;
@@ -392,9 +372,6 @@ static void drm_legacy_dev_reinit(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return;
 
-       atomic_set(&dev->ioctl_count, 0);
-       atomic_set(&dev->vma_count, 0);
-
        dev->sigdata.lock = NULL;
 
        dev->context_flag = 0;
@@ -438,7 +415,6 @@ int drm_lastclose(struct drm_device * dev)
 
        drm_legacy_dma_takedown(dev);
 
-       dev->dev_mapping = NULL;
        mutex_unlock(&dev->struct_mutex);
 
        drm_legacy_dev_reinit(dev);
@@ -462,7 +438,8 @@ int drm_lastclose(struct drm_device * dev)
 int drm_release(struct inode *inode, struct file *filp)
 {
        struct drm_file *file_priv = filp->private_data;
-       struct drm_device *dev = file_priv->minor->dev;
+       struct drm_minor *minor = file_priv->minor;
+       struct drm_device *dev = minor->dev;
        int retcode = 0;
 
        mutex_lock(&drm_global_mutex);
@@ -553,9 +530,6 @@ int drm_release(struct inode *inode, struct file *filp)
                }
        }
 
-       BUG_ON(dev->dev_mapping == NULL);
-       iput(container_of(dev->dev_mapping, struct inode, i_data));
-
        /* drop the reference held my the file priv */
        if (file_priv->master)
                drm_master_put(&file_priv->master);
@@ -578,17 +552,14 @@ int drm_release(struct inode *inode, struct file *filp)
         */
 
        if (!--dev->open_count) {
-               if (atomic_read(&dev->ioctl_count)) {
-                       DRM_ERROR("Device busy: %d\n",
-                                 atomic_read(&dev->ioctl_count));
-                       retcode = -EBUSY;
-               } else
-                       retcode = drm_lastclose(dev);
+               retcode = drm_lastclose(dev);
                if (drm_device_is_unplugged(dev))
                        drm_put_dev(dev);
        }
        mutex_unlock(&drm_global_mutex);
 
+       drm_minor_release(minor);
+
        return retcode;
 }
 EXPORT_SYMBOL(drm_release);