summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_file.c')
-rw-r--r--drivers/gpu/drm/drm_file.c48
1 files changed, 42 insertions, 6 deletions
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index 80d556402ab4..c4c704e01961 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -51,6 +51,37 @@
/* from BKL pushdown */
DEFINE_MUTEX(drm_global_mutex);
+bool drm_dev_needs_global_mutex(struct drm_device *dev)
+{
+ /*
+ * Legacy drivers rely on all kinds of BKL locking semantics, don't
+ * bother. They also still need BKL locking for their ioctls, so better
+ * safe than sorry.
+ */
+ if (drm_core_check_feature(dev, DRIVER_LEGACY))
+ return true;
+
+ /*
+ * The deprecated ->load callback must be called after the driver is
+ * already registered. This means such drivers rely on the BKL to make
+ * sure an open can't proceed until the driver is actually fully set up.
+ * Similar hilarity holds for the unload callback.
+ */
+ if (dev->driver->load || dev->driver->unload)
+ return true;
+
+ /*
+ * Drivers with the lastclose callback assume that it's synchronized
+ * against concurrent opens, which again needs the BKL. The proper fix
+ * is to use the drm_client infrastructure with proper locking for each
+ * client.
+ */
+ if (dev->driver->lastclose)
+ return true;
+
+ return false;
+}
+
/**
* DOC: file operations
*
@@ -378,9 +409,10 @@ int drm_open(struct inode *inode, struct file *filp)
if (IS_ERR(minor))
return PTR_ERR(minor);
- mutex_lock(&drm_global_mutex);
-
dev = minor->dev;
+ if (drm_dev_needs_global_mutex(dev))
+ mutex_lock(&drm_global_mutex);
+
if (!atomic_fetch_inc(&dev->open_count))
need_setup = 1;
@@ -398,13 +430,15 @@ int drm_open(struct inode *inode, struct file *filp)
}
}
- mutex_unlock(&drm_global_mutex);
+ if (drm_dev_needs_global_mutex(dev))
+ mutex_unlock(&drm_global_mutex);
return 0;
err_undo:
atomic_dec(&dev->open_count);
- mutex_unlock(&drm_global_mutex);
+ if (drm_dev_needs_global_mutex(dev))
+ mutex_unlock(&drm_global_mutex);
drm_minor_release(minor);
return retcode;
}
@@ -444,7 +478,8 @@ int drm_release(struct inode *inode, struct file *filp)
struct drm_minor *minor = file_priv->minor;
struct drm_device *dev = minor->dev;
- mutex_lock(&drm_global_mutex);
+ if (drm_dev_needs_global_mutex(dev))
+ mutex_lock(&drm_global_mutex);
DRM_DEBUG("open_count = %d\n", atomic_read(&dev->open_count));
@@ -453,7 +488,8 @@ int drm_release(struct inode *inode, struct file *filp)
if (atomic_dec_and_test(&dev->open_count))
drm_lastclose(dev);
- mutex_unlock(&drm_global_mutex);
+ if (drm_dev_needs_global_mutex(dev))
+ mutex_unlock(&drm_global_mutex);
drm_minor_release(minor);