summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2009-12-02 18:15:25 +0000
committerDave Airlie <airlied@redhat.com>2009-12-04 08:55:46 +1000
commit862302ffe422378a5213f558fc5cdf62c37050a9 (patch)
tree13557874eb479023e5a64f12990416045ea60818
parent9340d8cfeacd16cef1cbe94527f7baaed7640669 (diff)
drm: Add support for drm master_[set|drop] callbacks.
The vmwgfx driver has a per master rw lock around TTM, to guarantee mutual exclusion when needed. This is typically when all evictable buffers are evicted due to 1) vt switch 2) master switch 3) suspend / resume. In the multi-master case, on master switch the new master takes the previously active master lock in write mode, and then evicts all buffers. Any clients to previous masters will then block on that lock when trying to validate a buffer. fbdev also acts as a virtual master wrt this. Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_fops.c14
-rw-r--r--drivers/gpu/drm/drm_stub.c11
-rw-r--r--include/drm/drmP.h9
3 files changed, 34 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 8ac7fbf6b2b..08d14df3bb4 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -300,6 +300,18 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
goto out_free;
}
}
+ mutex_lock(&dev->struct_mutex);
+ if (dev->driver->master_set) {
+ ret = dev->driver->master_set(dev, priv, true);
+ if (ret) {
+ /* drop both references if this fails */
+ drm_master_put(&priv->minor->master);
+ drm_master_put(&priv->master);
+ mutex_unlock(&dev->struct_mutex);
+ goto out_free;
+ }
+ }
+ mutex_unlock(&dev->struct_mutex);
} else {
/* get a reference to the master */
priv->master = drm_master_get(priv->minor->master);
@@ -533,6 +545,8 @@ int drm_release(struct inode *inode, struct file *filp)
if (file_priv->minor->master == file_priv->master) {
/* drop the reference held my the minor */
+ if (dev->driver->master_drop)
+ dev->driver->master_drop(dev, file_priv, true);
drm_master_put(&file_priv->minor->master);
}
}
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index adb864dfef3..2c1b52847e9 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -174,6 +174,8 @@ void drm_master_put(struct drm_master **master)
int drm_setmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
+ int ret = 0;
+
if (file_priv->is_master)
return 0;
@@ -188,6 +190,13 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
mutex_lock(&dev->struct_mutex);
file_priv->minor->master = drm_master_get(file_priv->master);
file_priv->is_master = 1;
+ if (dev->driver->master_set) {
+ ret = dev->driver->master_set(dev, file_priv, false);
+ if (unlikely(ret != 0)) {
+ file_priv->is_master = 0;
+ drm_master_put(&file_priv->minor->master);
+ }
+ }
mutex_unlock(&dev->struct_mutex);
}
@@ -204,6 +213,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
mutex_lock(&dev->struct_mutex);
+ if (dev->driver->master_drop)
+ dev->driver->master_drop(dev, file_priv, false);
drm_master_put(&file_priv->minor->master);
file_priv->is_master = 0;
mutex_unlock(&dev->struct_mutex);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 1b72a526ba6..770772c014a 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -774,6 +774,15 @@ struct drm_driver {
/* Master routines */
int (*master_create)(struct drm_device *dev, struct drm_master *master);
void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
+ /**
+ * master_set is called whenever the minor master is set.
+ * master_drop is called whenever the minor master is dropped.
+ */
+
+ int (*master_set)(struct drm_device *dev, struct drm_file *file_priv,
+ bool from_open);
+ void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv,
+ bool from_release);
int (*proc_init)(struct drm_minor *minor);
void (*proc_cleanup)(struct drm_minor *minor);