Commit 862302ff authored by Thomas Hellstrom's avatar Thomas Hellstrom Committed by Dave Airlie

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: default avatarThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: default avatarJakob Bornecrantz <jakob@vmware.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 9340d8cf
...@@ -300,6 +300,18 @@ static int drm_open_helper(struct inode *inode, struct file *filp, ...@@ -300,6 +300,18 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
goto out_free; 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 { } else {
/* get a reference to the master */ /* get a reference to the master */
priv->master = drm_master_get(priv->minor->master); priv->master = drm_master_get(priv->minor->master);
...@@ -533,6 +545,8 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -533,6 +545,8 @@ int drm_release(struct inode *inode, struct file *filp)
if (file_priv->minor->master == file_priv->master) { if (file_priv->minor->master == file_priv->master) {
/* drop the reference held my the minor */ /* 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); drm_master_put(&file_priv->minor->master);
} }
} }
......
...@@ -174,6 +174,8 @@ void drm_master_put(struct drm_master **master) ...@@ -174,6 +174,8 @@ void drm_master_put(struct drm_master **master)
int drm_setmaster_ioctl(struct drm_device *dev, void *data, int drm_setmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
int ret = 0;
if (file_priv->is_master) if (file_priv->is_master)
return 0; return 0;
...@@ -188,6 +190,13 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, ...@@ -188,6 +190,13 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
file_priv->minor->master = drm_master_get(file_priv->master); file_priv->minor->master = drm_master_get(file_priv->master);
file_priv->is_master = 1; 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); mutex_unlock(&dev->struct_mutex);
} }
...@@ -204,6 +213,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, ...@@ -204,6 +213,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
return -EINVAL; return -EINVAL;
mutex_lock(&dev->struct_mutex); 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); drm_master_put(&file_priv->minor->master);
file_priv->is_master = 0; file_priv->is_master = 0;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
......
...@@ -774,6 +774,15 @@ struct drm_driver { ...@@ -774,6 +774,15 @@ struct drm_driver {
/* Master routines */ /* Master routines */
int (*master_create)(struct drm_device *dev, struct drm_master *master); int (*master_create)(struct drm_device *dev, struct drm_master *master);
void (*master_destroy)(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); int (*proc_init)(struct drm_minor *minor);
void (*proc_cleanup)(struct drm_minor *minor); void (*proc_cleanup)(struct drm_minor *minor);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment