Commit 7c1c2871 authored by Dave Airlie's avatar Dave Airlie Committed by Dave Airlie

drm: move to kref per-master structures.

This is step one towards having multiple masters sharing a drm
device in order to get fast-user-switching to work.

It splits out the information associated with the drm master
into a separate kref counted structure, and allocates this when
a master opens the device node. It also allows the current master
to abdicate (say while VT switched), and a new master to take over
the hardware.

It moves the Intel and radeon drivers to using the sarea from
within the new master structures.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent e7f7ab45
...@@ -45,14 +45,15 @@ ...@@ -45,14 +45,15 @@
* the one with matching magic number, while holding the drm_device::struct_mutex * the one with matching magic number, while holding the drm_device::struct_mutex
* lock. * lock.
*/ */
static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic) static struct drm_file *drm_find_file(struct drm_master *master, drm_magic_t magic)
{ {
struct drm_file *retval = NULL; struct drm_file *retval = NULL;
struct drm_magic_entry *pt; struct drm_magic_entry *pt;
struct drm_hash_item *hash; struct drm_hash_item *hash;
struct drm_device *dev = master->minor->dev;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
retval = pt->priv; retval = pt->priv;
} }
...@@ -71,11 +72,11 @@ static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic ...@@ -71,11 +72,11 @@ static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic
* associated the magic number hash key in drm_device::magiclist, while holding * associated the magic number hash key in drm_device::magiclist, while holding
* the drm_device::struct_mutex lock. * the drm_device::struct_mutex lock.
*/ */
static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, static int drm_add_magic(struct drm_master *master, struct drm_file *priv,
drm_magic_t magic) drm_magic_t magic)
{ {
struct drm_magic_entry *entry; struct drm_magic_entry *entry;
struct drm_device *dev = master->minor->dev;
DRM_DEBUG("%d\n", magic); DRM_DEBUG("%d\n", magic);
entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
...@@ -83,11 +84,10 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, ...@@ -83,11 +84,10 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
return -ENOMEM; return -ENOMEM;
memset(entry, 0, sizeof(*entry)); memset(entry, 0, sizeof(*entry));
entry->priv = priv; entry->priv = priv;
entry->hash_item.key = (unsigned long)magic; entry->hash_item.key = (unsigned long)magic;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
drm_ht_insert_item(&dev->magiclist, &entry->hash_item); drm_ht_insert_item(&master->magiclist, &entry->hash_item);
list_add_tail(&entry->head, &dev->magicfree); list_add_tail(&entry->head, &master->magicfree);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return 0; return 0;
...@@ -102,20 +102,21 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv, ...@@ -102,20 +102,21 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
* Searches and unlinks the entry in drm_device::magiclist with the magic * Searches and unlinks the entry in drm_device::magiclist with the magic
* number hash key, while holding the drm_device::struct_mutex lock. * number hash key, while holding the drm_device::struct_mutex lock.
*/ */
static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic) static int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
{ {
struct drm_magic_entry *pt; struct drm_magic_entry *pt;
struct drm_hash_item *hash; struct drm_hash_item *hash;
struct drm_device *dev = master->minor->dev;
DRM_DEBUG("%d\n", magic); DRM_DEBUG("%d\n", magic);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) { if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return -EINVAL; return -EINVAL;
} }
pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
drm_ht_remove_item(&dev->magiclist, hash); drm_ht_remove_item(&master->magiclist, hash);
list_del(&pt->head); list_del(&pt->head);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -153,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -153,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
++sequence; /* reserve 0 */ ++sequence; /* reserve 0 */
auth->magic = sequence++; auth->magic = sequence++;
spin_unlock(&lock); spin_unlock(&lock);
} while (drm_find_file(dev, auth->magic)); } while (drm_find_file(file_priv->master, auth->magic));
file_priv->magic = auth->magic; file_priv->magic = auth->magic;
drm_add_magic(dev, file_priv, auth->magic); drm_add_magic(file_priv->master, file_priv, auth->magic);
} }
DRM_DEBUG("%u\n", auth->magic); DRM_DEBUG("%u\n", auth->magic);
...@@ -181,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data, ...@@ -181,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data,
struct drm_file *file; struct drm_file *file;
DRM_DEBUG("%u\n", auth->magic); DRM_DEBUG("%u\n", auth->magic);
if ((file = drm_find_file(dev, auth->magic))) { if ((file = drm_find_file(file_priv->master, auth->magic))) {
file->authenticated = 1; file->authenticated = 1;
drm_remove_magic(dev, auth->magic); drm_remove_magic(file_priv->master, auth->magic);
return 0; return 0;
} }
return -EINVAL; return -EINVAL;
......
...@@ -54,9 +54,9 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, ...@@ -54,9 +54,9 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
{ {
struct drm_map_list *entry; struct drm_map_list *entry;
list_for_each_entry(entry, &dev->maplist, head) { list_for_each_entry(entry, &dev->maplist, head) {
if (entry->map && map->type == entry->map->type && if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) &&
((entry->map->offset == map->offset) || ((entry->map->offset == map->offset) ||
(map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
return entry; return entry;
} }
} }
...@@ -210,12 +210,12 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, ...@@ -210,12 +210,12 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
map->offset = (unsigned long)map->handle; map->offset = (unsigned long)map->handle;
if (map->flags & _DRM_CONTAINS_LOCK) { if (map->flags & _DRM_CONTAINS_LOCK) {
/* Prevent a 2nd X Server from creating a 2nd lock */ /* Prevent a 2nd X Server from creating a 2nd lock */
if (dev->lock.hw_lock != NULL) { if (dev->primary->master->lock.hw_lock != NULL) {
vfree(map->handle); vfree(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EBUSY; return -EBUSY;
} }
dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */ dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */
} }
break; break;
case _DRM_AGP: { case _DRM_AGP: {
...@@ -319,6 +319,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, ...@@ -319,6 +319,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
list->user_token = list->hash.key << PAGE_SHIFT; list->user_token = list->hash.key << PAGE_SHIFT;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
list->master = dev->primary->master;
*maplist = list; *maplist = list;
return 0; return 0;
} }
...@@ -345,7 +346,7 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data, ...@@ -345,7 +346,7 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
struct drm_map_list *maplist; struct drm_map_list *maplist;
int err; int err;
if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP)) if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP || map->type == _DRM_SHM))
return -EPERM; return -EPERM;
err = drm_addmap_core(dev, map->offset, map->size, map->type, err = drm_addmap_core(dev, map->offset, map->size, map->type,
...@@ -380,10 +381,12 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) ...@@ -380,10 +381,12 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
struct drm_map_list *r_list = NULL, *list_t; struct drm_map_list *r_list = NULL, *list_t;
drm_dma_handle_t dmah; drm_dma_handle_t dmah;
int found = 0; int found = 0;
struct drm_master *master;
/* Find the list entry for the map and remove it */ /* Find the list entry for the map and remove it */
list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
if (r_list->map == map) { if (r_list->map == map) {
master = r_list->master;
list_del(&r_list->head); list_del(&r_list->head);
drm_ht_remove_key(&dev->map_hash, drm_ht_remove_key(&dev->map_hash,
r_list->user_token >> PAGE_SHIFT); r_list->user_token >> PAGE_SHIFT);
...@@ -409,6 +412,13 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) ...@@ -409,6 +412,13 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
break; break;
case _DRM_SHM: case _DRM_SHM:
vfree(map->handle); vfree(map->handle);
if (master) {
if (dev->sigdata.lock == master->lock.hw_lock)
dev->sigdata.lock = NULL;
master->lock.hw_lock = NULL; /* SHM removed */
master->lock.file_priv = NULL;
wake_up_interruptible(&master->lock.lock_queue);
}
break; break;
case _DRM_AGP: case _DRM_AGP:
case _DRM_SCATTER_GATHER: case _DRM_SCATTER_GATHER:
......
...@@ -256,12 +256,13 @@ static int drm_context_switch(struct drm_device * dev, int old, int new) ...@@ -256,12 +256,13 @@ static int drm_context_switch(struct drm_device * dev, int old, int new)
* hardware lock is held, clears the drm_device::context_flag and wakes up * hardware lock is held, clears the drm_device::context_flag and wakes up
* drm_device::context_wait. * drm_device::context_wait.
*/ */
static int drm_context_switch_complete(struct drm_device * dev, int new) static int drm_context_switch_complete(struct drm_device *dev,
struct drm_file *file_priv, int new)
{ {
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
dev->last_switch = jiffies; dev->last_switch = jiffies;
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
DRM_ERROR("Lock isn't held after context switch\n"); DRM_ERROR("Lock isn't held after context switch\n");
} }
...@@ -420,7 +421,7 @@ int drm_newctx(struct drm_device *dev, void *data, ...@@ -420,7 +421,7 @@ int drm_newctx(struct drm_device *dev, void *data,
struct drm_ctx *ctx = data; struct drm_ctx *ctx = data;
DRM_DEBUG("%d\n", ctx->handle); DRM_DEBUG("%d\n", ctx->handle);
drm_context_switch_complete(dev, ctx->handle); drm_context_switch_complete(dev, file_priv, ctx->handle);
return 0; return 0;
} }
...@@ -442,9 +443,6 @@ int drm_rmctx(struct drm_device *dev, void *data, ...@@ -442,9 +443,6 @@ int drm_rmctx(struct drm_device *dev, void *data,
struct drm_ctx *ctx = data; struct drm_ctx *ctx = data;
DRM_DEBUG("%d\n", ctx->handle); DRM_DEBUG("%d\n", ctx->handle);
if (ctx->handle == DRM_KERNEL_CONTEXT + 1) {
file_priv->remove_auth_on_close = 1;
}
if (ctx->handle != DRM_KERNEL_CONTEXT) { if (ctx->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor) if (dev->driver->context_dtor)
dev->driver->context_dtor(dev, ctx->handle); dev->driver->context_dtor(dev, ctx->handle);
......
...@@ -74,6 +74,9 @@ static struct drm_ioctl_desc drm_ioctls[] = { ...@@ -74,6 +74,9 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH), DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
...@@ -138,8 +141,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { ...@@ -138,8 +141,6 @@ static struct drm_ioctl_desc drm_ioctls[] = {
*/ */
int drm_lastclose(struct drm_device * dev) int drm_lastclose(struct drm_device * dev)
{ {
struct drm_magic_entry *pt, *next;
struct drm_map_list *r_list, *list_t;
struct drm_vma_entry *vma, *vma_temp; struct drm_vma_entry *vma, *vma_temp;
int i; int i;
...@@ -149,12 +150,6 @@ int drm_lastclose(struct drm_device * dev) ...@@ -149,12 +150,6 @@ int drm_lastclose(struct drm_device * dev)
dev->driver->lastclose(dev); dev->driver->lastclose(dev);
DRM_DEBUG("driver lastclose completed\n"); DRM_DEBUG("driver lastclose completed\n");
if (dev->unique) {
drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
dev->unique = NULL;
dev->unique_len = 0;
}
if (dev->irq_enabled) if (dev->irq_enabled)
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
...@@ -164,16 +159,6 @@ int drm_lastclose(struct drm_device * dev) ...@@ -164,16 +159,6 @@ int drm_lastclose(struct drm_device * dev)
drm_drawable_free_all(dev); drm_drawable_free_all(dev);
del_timer(&dev->timer); del_timer(&dev->timer);
/* Clear pid list */
if (dev->magicfree.next) {
list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
list_del(&pt->head);
drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
}
drm_ht_remove(&dev->magiclist);
}
/* Clear AGP information */ /* Clear AGP information */
if (drm_core_has_AGP(dev) && dev->agp) { if (drm_core_has_AGP(dev) && dev->agp) {
struct drm_agp_mem *entry, *tempe; struct drm_agp_mem *entry, *tempe;
...@@ -205,13 +190,6 @@ int drm_lastclose(struct drm_device * dev) ...@@ -205,13 +190,6 @@ int drm_lastclose(struct drm_device * dev)
drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
} }
list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
if (!(r_list->map->flags & _DRM_DRIVER)) {
drm_rmmap_locked(dev, r_list->map);
r_list = NULL;
}
}
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
for (i = 0; i < dev->queue_count; i++) { for (i = 0; i < dev->queue_count; i++) {
if (dev->queuelist[i]) { if (dev->queuelist[i]) {
...@@ -231,11 +209,6 @@ int drm_lastclose(struct drm_device * dev) ...@@ -231,11 +209,6 @@ int drm_lastclose(struct drm_device * dev)
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
drm_dma_takedown(dev); drm_dma_takedown(dev);
if (dev->lock.hw_lock) {
dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
dev->lock.file_priv = NULL;
wake_up_interruptible(&dev->lock.lock_queue);
}
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("lastclose completed\n"); DRM_DEBUG("lastclose completed\n");
......
...@@ -44,10 +44,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, ...@@ -44,10 +44,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
static int drm_setup(struct drm_device * dev) static int drm_setup(struct drm_device * dev)
{ {
drm_local_map_t *map;
int i; int i;
int ret; int ret;
u32 sareapage;
if (dev->driver->firstopen) { if (dev->driver->firstopen) {
ret = dev->driver->firstopen(dev); ret = dev->driver->firstopen(dev);
...@@ -55,14 +53,6 @@ static int drm_setup(struct drm_device * dev) ...@@ -55,14 +53,6 @@ static int drm_setup(struct drm_device * dev)
return ret; return ret;
} }
dev->magicfree.next = NULL;
/* prebuild the SAREA */
sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE);
i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
if (i != 0)
return i;
atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->ioctl_count, 0);
atomic_set(&dev->vma_count, 0); atomic_set(&dev->vma_count, 0);
dev->buf_use = 0; dev->buf_use = 0;
...@@ -77,16 +67,12 @@ static int drm_setup(struct drm_device * dev) ...@@ -77,16 +67,12 @@ static int drm_setup(struct drm_device * dev)
for (i = 0; i < ARRAY_SIZE(dev->counts); i++) for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
atomic_set(&dev->counts[i], 0); atomic_set(&dev->counts[i], 0);
drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
INIT_LIST_HEAD(&dev->magicfree);
dev->sigdata.lock = NULL; dev->sigdata.lock = NULL;
init_waitqueue_head(&dev->lock.lock_queue);
dev->queue_count = 0; dev->queue_count = 0;
dev->queue_reserved = 0; dev->queue_reserved = 0;
dev->queue_slots = 0; dev->queue_slots = 0;
dev->queuelist = NULL; dev->queuelist = NULL;
dev->irq_enabled = 0;
dev->context_flag = 0; dev->context_flag = 0;
dev->interrupt_flag = 0; dev->interrupt_flag = 0;
dev->dma_flag = 0; dev->dma_flag = 0;
...@@ -265,10 +251,42 @@ static int drm_open_helper(struct inode *inode, struct file *filp, ...@@ -265,10 +251,42 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
goto out_free; goto out_free;
} }
/* if there is no current master make this fd it */
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (list_empty(&dev->filelist)) if (!priv->minor->master) {
priv->master = 1; /* create a new master */
priv->minor->master = drm_master_create(priv->minor);
if (!priv->minor->master) {
ret = -ENOMEM;
goto out_free;
}
priv->is_master = 1;
/* take another reference for the copy in the local file priv */
priv->master = drm_master_get(priv->minor->master);
priv->authenticated = 1;
mutex_unlock(&dev->struct_mutex);
if (dev->driver->master_create) {
ret = dev->driver->master_create(dev, priv->master);
if (ret) {
mutex_lock(&dev->struct_mutex);
/* 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;
}
}
} else {
/* get a reference to the master */
priv->master = drm_master_get(priv->minor->master);
mutex_unlock(&dev->struct_mutex);
}
mutex_lock(&dev->struct_mutex);
list_add(&priv->lhead, &dev->filelist); list_add(&priv->lhead, &dev->filelist);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -314,61 +332,33 @@ int drm_fasync(int fd, struct file *filp, int on) ...@@ -314,61 +332,33 @@ int drm_fasync(int fd, struct file *filp, int on)
} }
EXPORT_SYMBOL(drm_fasync); EXPORT_SYMBOL(drm_fasync);
/** /*
* Release file. * Reclaim locked buffers; note that this may be a bad idea if the current
* * context doesn't have the hw lock...
* \param inode device inode
* \param file_priv DRM file private.
* \return zero on success or a negative number on failure.
*
* If the hardware lock is held then free it, and take it again for the kernel
* context since it's necessary to reclaim buffers. Unlink the file private
* data from its list and free it. Decreases the open count and if it reaches
* zero calls drm_lastclose().
*/ */
int drm_release(struct inode *inode, struct file *filp) static void drm_reclaim_locked_buffers(struct drm_device *dev, struct file *f)
{ {
struct drm_file *file_priv = filp->private_data; struct drm_file *file_priv = f->private_data;
struct drm_device *dev = file_priv->minor->dev;
int retcode = 0;
lock_kernel();
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (dev->driver->preclose)
dev->driver->preclose(dev, file_priv);
/* ========================================================
* Begin inline drm_release
*/
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
task_pid_nr(current),
(long)old_encode_dev(file_priv->minor->device),
dev->open_count);
if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
if (drm_i_have_hw_lock(dev, file_priv)) { if (drm_i_have_hw_lock(dev, file_priv)) {
dev->driver->reclaim_buffers_locked(dev, file_priv); dev->driver->reclaim_buffers_locked(dev, file_priv);
} else { } else {
unsigned long endtime = jiffies + 3 * DRM_HZ; unsigned long _end = jiffies + 3 * DRM_HZ;
int locked = 0; int locked = 0;
drm_idlelock_take(&dev->lock); drm_idlelock_take(&file_priv->master->lock);
/* /*
* Wait for a while. * Wait for a while.
*/ */
do {
do{ spin_lock_bh(&file_priv->master->lock.spinlock);
spin_lock_bh(&dev->lock.spinlock); locked = file_priv->master->lock.idle_has_lock;
locked = dev->lock.idle_has_lock; spin_unlock_bh(&file_priv->master->lock.spinlock);
spin_unlock_bh(&dev->lock.spinlock);
if (locked) if (locked)
break; break;
schedule(); schedule();
} while (!time_after_eq(jiffies, endtime)); } while (!time_after_eq(jiffies, _end));
if (!locked) { if (!locked) {
DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
...@@ -377,31 +367,76 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -377,31 +367,76 @@ int drm_release(struct inode *inode, struct file *filp)
} }
dev->driver->reclaim_buffers_locked(dev, file_priv); dev->driver->reclaim_buffers_locked(dev, file_priv);
drm_idlelock_release(&dev->lock); drm_idlelock_release(&file_priv->master->lock);
}
} }
}
if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { static void drm_master_release(struct drm_device *dev, struct file *filp)
{
struct drm_file *file_priv = filp->private_data;
drm_idlelock_take(&dev->lock); if (dev->driver->reclaim_buffers_locked &&
dev->driver->reclaim_buffers_idlelocked(dev, file_priv); file_priv->master->lock.hw_lock)
drm_idlelock_release(&dev->lock); drm_reclaim_locked_buffers(dev, filp);
if (dev->driver->reclaim_buffers_idlelocked &&
file_priv->master->lock.hw_lock) {
drm_idlelock_take(&file_priv->master->lock);
dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
drm_idlelock_release(&file_priv->master->lock);
} }
if (drm_i_have_hw_lock(dev, file_priv)) { if (drm_i_have_hw_lock(dev, file_priv)) {
DRM_DEBUG("File %p released, freeing lock for context %d\n", DRM_DEBUG("File %p released, freeing lock for context %d\n",
filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
drm_lock_free(&file_priv->master->lock,
drm_lock_free(&dev->lock, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
} }
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
!dev->driver->reclaim_buffers_locked) { !dev->driver->reclaim_buffers_locked) {
dev->driver->reclaim_buffers(dev, file_priv); dev->driver->reclaim_buffers(dev, file_priv);
} }
}
/**
* Release file.
*
* \param inode device inode
* \param file_priv DRM file private.
* \return zero on success or a negative number on failure.
*
* If the hardware lock is held then free it, and take it again for the kernel
* context since it's necessary to reclaim buffers. Unlink the file private
* data from its list and free it. Decreases the open count and if it reaches
* zero calls drm_lastclose().
*/
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;
int retcode = 0;
lock_kernel();
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (dev->driver->preclose)
dev->driver->preclose(dev, file_priv);
/* ========================================================
* Begin inline drm_release
*/
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
task_pid_nr(current),
(long)old_encode_dev(file_priv->minor->device),
dev->open_count);
/* if the master has gone away we can't do anything with the lock */
if (file_priv->minor->master)
drm_master_release(dev, filp);
if (dev->driver->driver_features & DRIVER_GEM) if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_release(dev, file_priv); drm_gem_release(dev, file_priv);
...@@ -428,12 +463,24 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -428,12 +463,24 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_unlock(&dev->ctxlist_mutex); mutex_unlock(&dev->ctxlist_mutex);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
if (file_priv->remove_auth_on_close == 1) {
struct drm_file *temp;
list_for_each_entry(temp, &dev->filelist, lhead) if (file_priv->is_master) {
struct drm_file *temp;
list_for_each_entry(temp, &dev->filelist, lhead) {
if ((temp->master == file_priv->master) &&
(temp != file_priv))
temp->authenticated = 0; temp->authenticated = 0;
} }
if (file_priv->minor->master == file_priv->master) {
/* drop the reference held my the minor */
drm_master_put(&file_priv->minor->master);
}
}
/* drop the reference held my the file priv */
drm_master_put(&file_priv->master);
file_priv->is_master = 0;
list_del(&file_priv->lhead); list_del(&file_priv->lhead);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -448,9 +495,9 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -448,9 +495,9 @@ int drm_release(struct inode *inode, struct file *filp)
atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
spin_lock(&dev->count_lock); spin_lock(&dev->count_lock);
if (!--dev->open_count) { if (!--dev->open_count) {
if (atomic_read(&dev->ioctl_count) || dev->blocked) { if (atomic_read(&dev->ioctl_count)) {
DRM_ERROR("Device busy: %d %d\n", DRM_ERROR("Device busy: %d\n",
atomic_read(&dev->ioctl_count), dev->blocked); atomic_read(&dev->ioctl_count));
spin_unlock(&dev->count_lock); spin_unlock(&dev->count_lock);
unlock_kernel(); unlock_kernel();
return -EBUSY; return -EBUSY;
......
...@@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data, ...@@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_unique *u = data; struct drm_unique *u = data;
struct drm_master *master = file_priv->master;
if (u->unique_len >= dev->unique_len) { if (u->unique_len >= master->unique_len) {
if (copy_to_user(u->unique, dev->unique, dev->unique_len)) if (copy_to_user(u->unique, master->unique, master->unique_len))
return -EFAULT; return -EFAULT;
} }
u->unique_len = dev->unique_len; u->unique_len = master->unique_len;
return 0; return 0;
} }
...@@ -81,36 +82,37 @@ int drm_setunique(struct drm_device *dev, void *data, ...@@ -81,36 +82,37 @@ int drm_setunique(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_unique *u = data; struct drm_unique *u = data;
struct drm_master *master = file_priv->master;
int domain, bus, slot, func, ret; int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique) if (master->unique_len || master->unique)
return -EBUSY; return -EBUSY;
if (!u->unique_len || u->unique_len > 1024) if (!u->unique_len || u->unique_len > 1024)
return -EINVAL; return -EINVAL;
dev->unique_len = u->unique_len; master->unique_len = u->unique_len;
dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); master->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
if (!dev->unique) if (!master->unique)
return -ENOMEM; return -ENOMEM;
if (copy_from_user(dev->unique, u->unique, dev->unique_len)) if (copy_from_user(master->unique, u->unique, master->unique_len))
return -EFAULT; return -EFAULT;
dev->unique[dev->unique_len] = '\0'; master->unique[master->unique_len] = '\0';
dev->devname = dev->devname =
drm_alloc(strlen(dev->driver->pci_driver.name) + drm_alloc(strlen(dev->driver->pci_driver.name) +
strlen(dev->unique) + 2, DRM_MEM_DRIVER); strlen(master->unique) + 2, DRM_MEM_DRIVER);
if (!dev->devname) if (!dev->devname)
return -ENOMEM; return -ENOMEM;
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
dev->unique); master->unique);
/* Return error if the busid submitted doesn't match the device's actual /* Return error if the busid submitted doesn't match the device's actual
* busid. * busid.
*/ */
ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
if (ret != 3) if (ret != 3)
return -EINVAL; return -EINVAL;
domain = bus >> 8; domain = bus >> 8;
...@@ -125,34 +127,35 @@ int drm_setunique(struct drm_device *dev, void *data, ...@@ -125,34 +127,35 @@ int drm_setunique(struct drm_device *dev, void *data,
return 0; return 0;
} }
static int drm_set_busid(struct drm_device * dev) static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
{ {
struct drm_master *master = file_priv->master;
int len; int len;
if (dev->unique != NULL) if (master->unique != NULL)
return 0; return -EBUSY;
dev->unique_len = 40; master->unique_len = 40;
dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); master->unique = drm_alloc(master->unique_len + 1, DRM_MEM_DRIVER);
if (dev->unique == NULL) if (master->unique == NULL)
return -ENOMEM; return -ENOMEM;
len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",
drm_get_pci_domain(dev), dev->pdev->bus->number, drm_get_pci_domain(dev),
dev->pdev->bus->number,
PCI_SLOT(dev->pdev->devfn), PCI_SLOT(dev->pdev->devfn),
PCI_FUNC(dev->pdev->devfn)); PCI_FUNC(dev->pdev->devfn));
if (len > master->unique_len)
if (len > dev->unique_len) DRM_ERROR("buffer overflow");
DRM_ERROR("Unique buffer overflowed\n");
dev->devname = dev->devname =
drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len +
2, DRM_MEM_DRIVER); 2, DRM_MEM_DRIVER);
if (dev->devname == NULL) if (dev->devname == NULL)
return -ENOMEM; return -ENOMEM;
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
dev->unique); master->unique);
return 0; return 0;
} }
...@@ -276,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data, ...@@ -276,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data,
for (i = 0; i < dev->counters; i++) { for (i = 0; i < dev->counters; i++) {
if (dev->types[i] == _DRM_STAT_LOCK) if (dev->types[i] == _DRM_STAT_LOCK)
stats->data[i].value = stats->data[i].value =
(dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0);
else else
stats->data[i].value = atomic_read(&dev->counts[i]); stats->data[i].value = atomic_read(&dev->counts[i]);
stats->data[i].type = dev->types[i]; stats->data[i].type = dev->types[i];
...@@ -318,7 +321,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri ...@@ -318,7 +321,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
/* /*
* Version 1.1 includes tying of DRM to specific device * Version 1.1 includes tying of DRM to specific device
*/ */
drm_set_busid(dev); drm_set_busid(dev, file_priv);
} }
} }
......
...@@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
{ {
DECLARE_WAITQUEUE(entry, current); DECLARE_WAITQUEUE(entry, current);
struct drm_lock *lock = data; struct drm_lock *lock = data;
struct drm_master *master = file_priv->master;
int ret = 0; int ret = 0;
++file_priv->lock_count; ++file_priv->lock_count;
...@@ -64,26 +65,27 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -64,26 +65,27 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
lock->context, task_pid_nr(current), lock->context, task_pid_nr(current),
dev->lock.hw_lock->lock, lock->flags); master->lock.hw_lock->lock, lock->flags);
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
if (lock->context < 0) if (lock->context < 0)
return -EINVAL; return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry); add_wait_queue(&master->lock.lock_queue, &entry);
spin_lock_bh(&dev->lock.spinlock); spin_lock_bh(&master->lock.spinlock);
dev->lock.user_waiters++; master->lock.user_waiters++;
spin_unlock_bh(&dev->lock.spinlock); spin_unlock_bh(&master->lock.spinlock);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) { if (!master->lock.hw_lock) {
/* Device has been unregistered */ /* Device has been unregistered */
ret = -EINTR; ret = -EINTR;
break; break;
} }
if (drm_lock_take(&dev->lock, lock->context)) { if (drm_lock_take(&master->lock, lock->context)) {
dev->lock.file_priv = file_priv; master->lock.file_priv = file_priv;
dev->lock.lock_time = jiffies; master->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
break; /* Got lock */ break; /* Got lock */
} }
...@@ -95,11 +97,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -95,11 +97,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
break; break;
} }
} }
spin_lock_bh(&dev->lock.spinlock); spin_lock_bh(&master->lock.spinlock);
dev->lock.user_waiters--; master->lock.user_waiters--;
spin_unlock_bh(&dev->lock.spinlock); spin_unlock_bh(&master->lock.spinlock);
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry); remove_wait_queue(&master->lock.lock_queue, &entry);
DRM_DEBUG("%d %s\n", lock->context, DRM_DEBUG("%d %s\n", lock->context,
ret ? "interrupted" : "has lock"); ret ? "interrupted" : "has lock");
...@@ -108,14 +110,14 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -108,14 +110,14 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
/* don't set the block all signals on the master process for now /* don't set the block all signals on the master process for now
* really probably not the correct answer but lets us debug xkb * really probably not the correct answer but lets us debug xkb
* xserver for now */ * xserver for now */
if (!file_priv->master) { if (!file_priv->is_master) {
sigemptyset(&dev->sigmask); sigemptyset(&dev->sigmask);
sigaddset(&dev->sigmask, SIGSTOP); sigaddset(&dev->sigmask, SIGSTOP);
sigaddset(&dev->sigmask, SIGTSTP); sigaddset(&dev->sigmask, SIGTSTP);
sigaddset(&dev->sigmask, SIGTTIN); sigaddset(&dev->sigmask, SIGTTIN);
sigaddset(&dev->sigmask, SIGTTOU); sigaddset(&dev->sigmask, SIGTTOU);
dev->sigdata.context = lock->context; dev->sigdata.context = lock->context;
dev->sigdata.lock = dev->lock.hw_lock; dev->sigdata.lock = master->lock.hw_lock;
block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
} }
...@@ -154,6 +156,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -154,6 +156,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
{ {
struct drm_lock *lock = data; struct drm_lock *lock = data;
struct drm_master *master = file_priv->master;
if (lock->context == DRM_KERNEL_CONTEXT) { if (lock->context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n", DRM_ERROR("Process %d using kernel context %d\n",
...@@ -169,7 +172,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -169,7 +172,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
if (dev->driver->kernel_context_switch_unlock) if (dev->driver->kernel_context_switch_unlock)
dev->driver->kernel_context_switch_unlock(dev); dev->driver->kernel_context_switch_unlock(dev);
else { else {
if (drm_lock_free(&dev->lock,lock->context)) { if (drm_lock_free(&master->lock, lock->context)) {
/* FIXME: Should really bail out here. */ /* FIXME: Should really bail out here. */
} }
} }
...@@ -379,9 +382,10 @@ EXPORT_SYMBOL(drm_idlelock_release); ...@@ -379,9 +382,10 @@ EXPORT_SYMBOL(drm_idlelock_release);
int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
{ {
return (file_priv->lock_count && dev->lock.hw_lock && struct drm_master *master = file_priv->master;
_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && return (file_priv->lock_count && master->lock.hw_lock &&
dev->lock.file_priv == file_priv); _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
master->lock.file_priv == file_priv);
} }
EXPORT_SYMBOL(drm_i_have_hw_lock); EXPORT_SYMBOL(drm_i_have_hw_lock);
...@@ -195,6 +195,7 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, ...@@ -195,6 +195,7 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data) int *eof, void *data)
{ {
struct drm_minor *minor = (struct drm_minor *) data; struct drm_minor *minor = (struct drm_minor *) data;
struct drm_master *master = minor->master;
struct drm_device *dev = minor->dev; struct drm_device *dev = minor->dev;
int len = 0; int len = 0;
...@@ -203,13 +204,16 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, ...@@ -203,13 +204,16 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,
return 0; return 0;
} }
if (!master)
return 0;
*start = &buf[offset]; *start = &buf[offset];
*eof = 0; *eof = 0;
if (dev->unique) { if (master->unique) {
DRM_PROC_PRINT("%s %s %s\n", DRM_PROC_PRINT("%s %s %s\n",
dev->driver->pci_driver.name, dev->driver->pci_driver.name,
pci_name(dev->pdev), dev->unique); pci_name(dev->pdev), master->unique);
} else { } else {
DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name,
pci_name(dev->pdev)); pci_name(dev->pdev));
......
...@@ -79,6 +79,104 @@ again: ...@@ -79,6 +79,104 @@ again:
return new_id; return new_id;
} }
struct drm_master *drm_master_create(struct drm_minor *minor)
{
struct drm_master *master;
master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER);
if (!master)
return NULL;
kref_init(&master->refcount);
spin_lock_init(&master->lock.spinlock);
init_waitqueue_head(&master->lock.lock_queue);
drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
INIT_LIST_HEAD(&master->magicfree);
master->minor = minor;
list_add_tail(&master->head, &minor->master_list);
return master;
}
struct drm_master *drm_master_get(struct drm_master *master)
{
kref_get(&master->refcount);
return master;
}
static void drm_master_destroy(struct kref *kref)
{
struct drm_master *master = container_of(kref, struct drm_master, refcount);
struct drm_magic_entry *pt, *next;
struct drm_device *dev = master->minor->dev;
list_del(&master->head);
if (dev->driver->master_destroy)
dev->driver->master_destroy(dev, master);
if (master->unique) {
drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER);
master->unique = NULL;
master->unique_len = 0;
}
list_for_each_entry_safe(pt, next, &master->magicfree, head) {
list_del(&pt->head);
drm_ht_remove_item(&master->magiclist, &pt->hash_item);
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
}
drm_ht_remove(&master->magiclist);
if (master->lock.hw_lock) {
if (dev->sigdata.lock == master->lock.hw_lock)
dev->sigdata.lock = NULL;
master->lock.hw_lock = NULL;
master->lock.file_priv = NULL;
wake_up_interruptible(&master->lock.lock_queue);
}
drm_free(master, sizeof(*master), DRM_MEM_DRIVER);
}
void drm_master_put(struct drm_master **master)
{
kref_put(&(*master)->refcount, drm_master_destroy);
*master = NULL;
}
int drm_setmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
return -EINVAL;
if (!file_priv->master)
return -EINVAL;
if (!file_priv->minor->master &&
file_priv->minor->master != file_priv->master) {
mutex_lock(&dev->struct_mutex);
file_priv->minor->master = drm_master_get(file_priv->master);
mutex_lock(&dev->struct_mutex);
}
return 0;
}
int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
if (!file_priv->master)
return -EINVAL;
mutex_lock(&dev->struct_mutex);
drm_master_put(&file_priv->minor->master);
mutex_unlock(&dev->struct_mutex);
return 0;
}
static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
const struct pci_device_id *ent, const struct pci_device_id *ent,
struct drm_driver *driver) struct drm_driver *driver)
...@@ -92,7 +190,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, ...@@ -92,7 +190,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
spin_lock_init(&dev->count_lock); spin_lock_init(&dev->count_lock);
spin_lock_init(&dev->drw_lock); spin_lock_init(&dev->drw_lock);
spin_lock_init(&dev->lock.spinlock);
init_timer(&dev->timer); init_timer(&dev->timer);
mutex_init(&dev->struct_mutex); mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex); mutex_init(&dev->ctxlist_mutex);
...@@ -200,6 +297,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t ...@@ -200,6 +297,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
new_minor->device = MKDEV(DRM_MAJOR, minor_id); new_minor->device = MKDEV(DRM_MAJOR, minor_id);
new_minor->dev = dev; new_minor->dev = dev;
new_minor->index = minor_id; new_minor->index = minor_id;
INIT_LIST_HEAD(&new_minor->master_list);
idr_replace(&drm_minors_idr, new_minor, minor_id); idr_replace(&drm_minors_idr, new_minor, minor_id);
...@@ -299,11 +397,6 @@ int drm_put_dev(struct drm_device * dev) ...@@ -299,11 +397,6 @@ int drm_put_dev(struct drm_device * dev)
{ {
DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name); DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
if (dev->unique) {
drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
dev->unique = NULL;
dev->unique_len = 0;
}
if (dev->devname) { if (dev->devname) {
drm_free(dev->devname, strlen(dev->devname) + 1, drm_free(dev->devname, strlen(dev->devname) + 1,
DRM_MEM_DRIVER); DRM_MEM_DRIVER);
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
int i915_wait_ring(struct drm_device * dev, int n, const char *caller) int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring); drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
u32 last_acthd = I915_READ(acthd_reg); u32 last_acthd = I915_READ(acthd_reg);
...@@ -55,8 +56,8 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) ...@@ -55,8 +56,8 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
if (ring->space >= n) if (ring->space >= n)
return 0; return 0;
if (dev_priv->sarea_priv) if (master_priv->sarea_priv)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
if (ring->head != last_head) if (ring->head != last_head)
i = 0; i = 0;
...@@ -121,6 +122,7 @@ static void i915_free_hws(struct drm_device *dev) ...@@ -121,6 +122,7 @@ static void i915_free_hws(struct drm_device *dev)
void i915_kernel_lost_context(struct drm_device * dev) void i915_kernel_lost_context(struct drm_device * dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring); drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
...@@ -129,8 +131,12 @@ void i915_kernel_lost_context(struct drm_device * dev) ...@@ -129,8 +131,12 @@ void i915_kernel_lost_context(struct drm_device * dev)
if (ring->space < 0) if (ring->space < 0)
ring->space += ring->Size; ring->space += ring->Size;
if (ring->head == ring->tail && dev_priv->sarea_priv) if (!dev->primary->master)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; return;
master_priv = dev->primary->master->driver_priv;
if (ring->head == ring->tail && master_priv->sarea_priv)
master_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
} }
static int i915_dma_cleanup(struct drm_device * dev) static int i915_dma_cleanup(struct drm_device * dev)
...@@ -154,25 +160,13 @@ static int i915_dma_cleanup(struct drm_device * dev) ...@@ -154,25 +160,13 @@ static int i915_dma_cleanup(struct drm_device * dev)
if (I915_NEED_GFX_HWS(dev)) if (I915_NEED_GFX_HWS(dev))
i915_free_hws(dev); i915_free_hws(dev);
dev_priv->sarea = NULL;
dev_priv->sarea_priv = NULL;
return 0; return 0;
} }
static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
i915_dma_cleanup(dev);
return -EINVAL;
}
dev_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
if (init->ring_size != 0) { if (init->ring_size != 0) {
if (dev_priv->ring.ring_obj != NULL) { if (dev_priv->ring.ring_obj != NULL) {
...@@ -207,7 +201,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) ...@@ -207,7 +201,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
dev_priv->back_offset = init->back_offset; dev_priv->back_offset = init->back_offset;
dev_priv->front_offset = init->front_offset; dev_priv->front_offset = init->front_offset;
dev_priv->current_page = 0; dev_priv->current_page = 0;
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; if (master_priv->sarea_priv)
master_priv->sarea_priv->pf_current_page = 0;
/* Allow hardware batchbuffers unless told otherwise. /* Allow hardware batchbuffers unless told otherwise.
*/ */
...@@ -222,11 +217,6 @@ static int i915_dma_resume(struct drm_device * dev) ...@@ -222,11 +217,6 @@ static int i915_dma_resume(struct drm_device * dev)
DRM_DEBUG("%s\n", __func__); DRM_DEBUG("%s\n", __func__);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
return -EINVAL;
}
if (dev_priv->ring.map.handle == NULL) { if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for" DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n"); " ring buffer\n");
...@@ -435,13 +425,14 @@ i915_emit_box(struct drm_device *dev, ...@@ -435,13 +425,14 @@ i915_emit_box(struct drm_device *dev,
static void i915_emit_breadcrumb(struct drm_device *dev) static void i915_emit_breadcrumb(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
RING_LOCALS; RING_LOCALS;
dev_priv->counter++; dev_priv->counter++;
if (dev_priv->counter > 0x7FFFFFFFUL) if (dev_priv->counter > 0x7FFFFFFFUL)
dev_priv->counter = 0; dev_priv->counter = 0;
if (dev_priv->sarea_priv) if (master_priv->sarea_priv)
dev_priv->sarea_priv->last_enqueue = dev_priv->counter; master_priv->sarea_priv->last_enqueue = dev_priv->counter;
BEGIN_LP_RING(4); BEGIN_LP_RING(4);
OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(MI_STORE_DWORD_INDEX);
...@@ -537,15 +528,17 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, ...@@ -537,15 +528,17 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
static int i915_dispatch_flip(struct drm_device * dev) static int i915_dispatch_flip(struct drm_device * dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv =
dev->primary->master->driver_priv;
RING_LOCALS; RING_LOCALS;
if (!dev_priv->sarea_priv) if (!master_priv->sarea_priv)
return -EINVAL; return -EINVAL;
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
__func__, __func__,
dev_priv->current_page, dev_priv->current_page,
dev_priv->sarea_priv->pf_current_page); master_priv->sarea_priv->pf_current_page);
i915_kernel_lost_context(dev); i915_kernel_lost_context(dev);
...@@ -572,7 +565,7 @@ static int i915_dispatch_flip(struct drm_device * dev) ...@@ -572,7 +565,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
OUT_RING(0); OUT_RING(0);
ADVANCE_LP_RING(); ADVANCE_LP_RING();
dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; master_priv->sarea_priv->last_enqueue = dev_priv->counter++;
BEGIN_LP_RING(4); BEGIN_LP_RING(4);
OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(MI_STORE_DWORD_INDEX);
...@@ -581,7 +574,7 @@ static int i915_dispatch_flip(struct drm_device * dev) ...@@ -581,7 +574,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
OUT_RING(0); OUT_RING(0);
ADVANCE_LP_RING(); ADVANCE_LP_RING();
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
return 0; return 0;
} }
...@@ -611,8 +604,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, ...@@ -611,8 +604,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv; master_priv->sarea_priv;
drm_i915_batchbuffer_t *batch = data; drm_i915_batchbuffer_t *batch = data;
int ret; int ret;
...@@ -644,8 +638,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, ...@@ -644,8 +638,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv; master_priv->sarea_priv;
drm_i915_cmdbuffer_t *cmdbuf = data; drm_i915_cmdbuffer_t *cmdbuf = data;
int ret; int ret;
...@@ -802,6 +797,30 @@ static int i915_set_status_page(struct drm_device *dev, void *data, ...@@ -802,6 +797,30 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
return 0; return 0;
} }
int i915_master_create(struct drm_device *dev, struct drm_master *master)
{
struct drm_i915_master_private *master_priv;
master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER);
if (!master_priv)
return -ENOMEM;
master->driver_priv = master_priv;
return 0;
}
void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
{
struct drm_i915_master_private *master_priv = master->driver_priv;
if (!master_priv)
return;
drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER);
master->driver_priv = NULL;
}
int i915_driver_load(struct drm_device *dev, unsigned long flags) int i915_driver_load(struct drm_device *dev, unsigned long flags)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
......
...@@ -107,6 +107,8 @@ static struct drm_driver driver = { ...@@ -107,6 +107,8 @@ static struct drm_driver driver = {
.reclaim_buffers = drm_core_reclaim_buffers, .reclaim_buffers = drm_core_reclaim_buffers,
.get_map_ofs = drm_core_get_map_ofs, .get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs, .get_reg_ofs = drm_core_get_reg_ofs,
.master_create = i915_master_create,
.master_destroy = i915_master_destroy,
.proc_init = i915_gem_proc_init, .proc_init = i915_gem_proc_init,
.proc_cleanup = i915_gem_proc_cleanup, .proc_cleanup = i915_gem_proc_cleanup,
.gem_init_object = i915_gem_init_object, .gem_init_object = i915_gem_init_object,
......
...@@ -103,15 +103,18 @@ struct intel_opregion { ...@@ -103,15 +103,18 @@ struct intel_opregion {
int enabled; int enabled;
}; };
struct drm_i915_master_private {
drm_local_map_t *sarea;
struct _drm_i915_sarea *sarea_priv;
};
typedef struct drm_i915_private { typedef struct drm_i915_private {
struct drm_device *dev; struct drm_device *dev;
int has_gem; int has_gem;
void __iomem *regs; void __iomem *regs;
drm_local_map_t *sarea;
drm_i915_sarea_t *sarea_priv;
drm_i915_ring_buffer_t ring; drm_i915_ring_buffer_t ring;
drm_dma_handle_t *status_page_dmah; drm_dma_handle_t *status_page_dmah;
...@@ -417,6 +420,9 @@ struct drm_i915_file_private { ...@@ -417,6 +420,9 @@ struct drm_i915_file_private {
extern struct drm_ioctl_desc i915_ioctls[]; extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl; extern int i915_max_ioctl;
extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
/* i915_dma.c */ /* i915_dma.c */
extern void i915_kernel_lost_context(struct drm_device * dev); extern void i915_kernel_lost_context(struct drm_device * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags); extern int i915_driver_load(struct drm_device *, unsigned long flags);
......
...@@ -168,6 +168,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -168,6 +168,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *) arg; struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
struct drm_i915_master_private *master_priv;
u32 iir, new_iir; u32 iir, new_iir;
u32 pipea_stats, pipeb_stats; u32 pipea_stats, pipeb_stats;
u32 vblank_status; u32 vblank_status;
...@@ -222,9 +223,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -222,9 +223,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
I915_WRITE(IIR, iir); I915_WRITE(IIR, iir);
new_iir = I915_READ(IIR); /* Flush posted writes */ new_iir = I915_READ(IIR); /* Flush posted writes */
if (dev_priv->sarea_priv) if (dev->primary->master) {
dev_priv->sarea_priv->last_dispatch = master_priv = dev->primary->master->driver_priv;
if (master_priv->sarea_priv)
master_priv->sarea_priv->last_dispatch =
READ_BREADCRUMB(dev_priv); READ_BREADCRUMB(dev_priv);
}
if (iir & I915_USER_INTERRUPT) { if (iir & I915_USER_INTERRUPT) {
dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
...@@ -269,6 +273,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ...@@ -269,6 +273,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
static int i915_emit_irq(struct drm_device * dev) static int i915_emit_irq(struct drm_device * dev)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
RING_LOCALS; RING_LOCALS;
i915_kernel_lost_context(dev); i915_kernel_lost_context(dev);
...@@ -278,8 +283,8 @@ static int i915_emit_irq(struct drm_device * dev) ...@@ -278,8 +283,8 @@ static int i915_emit_irq(struct drm_device * dev)
dev_priv->counter++; dev_priv->counter++;
if (dev_priv->counter > 0x7FFFFFFFUL) if (dev_priv->counter > 0x7FFFFFFFUL)
dev_priv->counter = 1; dev_priv->counter = 1;
if (dev_priv->sarea_priv) if (master_priv->sarea_priv)
dev_priv->sarea_priv->last_enqueue = dev_priv->counter; master_priv->sarea_priv->last_enqueue = dev_priv->counter;
BEGIN_LP_RING(4); BEGIN_LP_RING(4);
OUT_RING(MI_STORE_DWORD_INDEX); OUT_RING(MI_STORE_DWORD_INDEX);
...@@ -317,21 +322,20 @@ void i915_user_irq_put(struct drm_device *dev) ...@@ -317,21 +322,20 @@ void i915_user_irq_put(struct drm_device *dev)
static int i915_wait_irq(struct drm_device * dev, int irq_nr) static int i915_wait_irq(struct drm_device * dev, int irq_nr)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
int ret = 0; int ret = 0;
DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
READ_BREADCRUMB(dev_priv)); READ_BREADCRUMB(dev_priv));
if (READ_BREADCRUMB(dev_priv) >= irq_nr) { if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
if (dev_priv->sarea_priv) { if (master_priv->sarea_priv)
dev_priv->sarea_priv->last_dispatch = master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
READ_BREADCRUMB(dev_priv);
}
return 0; return 0;
} }
if (dev_priv->sarea_priv) if (master_priv->sarea_priv)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
i915_user_irq_get(dev); i915_user_irq_get(dev);
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
...@@ -343,10 +347,6 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) ...@@ -343,10 +347,6 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
} }
if (dev_priv->sarea_priv)
dev_priv->sarea_priv->last_dispatch =
READ_BREADCRUMB(dev_priv);
return ret; return ret;
} }
......
...@@ -46,7 +46,8 @@ ...@@ -46,7 +46,8 @@
static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
{ {
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
drm_i915_sarea_t *sarea_priv = master_priv->sarea_priv;
struct drm_tex_region *list; struct drm_tex_region *list;
unsigned shift, nr; unsigned shift, nr;
unsigned start; unsigned start;
......
...@@ -860,12 +860,12 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv) ...@@ -860,12 +860,12 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
* The actual age emit is done by r300_do_cp_cmdbuf, which is why you must * The actual age emit is done by r300_do_cp_cmdbuf, which is why you must
* be careful about how this function is called. * be careful about how this function is called.
*/ */
static void r300_discard_buffer(struct drm_device * dev, struct drm_buf * buf) static void r300_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf)
{ {
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_buf_priv_t *buf_priv = buf->dev_private; drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
struct drm_radeon_master_private *master_priv = master->driver_priv;
buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
buf->pending = 1; buf->pending = 1;
buf->used = 0; buf->used = 0;
} }
...@@ -1027,6 +1027,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, ...@@ -1027,6 +1027,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
drm_radeon_kcmd_buffer_t *cmdbuf) drm_radeon_kcmd_buffer_t *cmdbuf)
{ {
drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
struct drm_device_dma *dma = dev->dma; struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf = NULL; struct drm_buf *buf = NULL;
int emit_dispatch_age = 0; int emit_dispatch_age = 0;
...@@ -1134,7 +1135,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, ...@@ -1134,7 +1135,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
} }
emit_dispatch_age = 1; emit_dispatch_age = 1;
r300_discard_buffer(dev, buf); r300_discard_buffer(dev, file_priv->master, buf);
break; break;
case R300_CMD_WAIT: case R300_CMD_WAIT:
...@@ -1189,7 +1190,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, ...@@ -1189,7 +1190,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
/* Emit the vertex buffer age */ /* Emit the vertex buffer age */
BEGIN_RING(2); BEGIN_RING(2);
RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch); RADEON_DISPATCH_AGE(master_priv->sarea_priv->last_dispatch);
ADVANCE_RING(); ADVANCE_RING();
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
#include "drm_sarea.h"
#include "radeon_drm.h" #include "radeon_drm.h"
#include "radeon_drv.h" #include "radeon_drv.h"
#include "r300_reg.h" #include "r300_reg.h"
...@@ -667,15 +668,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, ...@@ -667,15 +668,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
RADEON_WRITE(RADEON_BUS_CNTL, tmp); RADEON_WRITE(RADEON_BUS_CNTL, tmp);
} /* PCIE cards appears to not need this */ } /* PCIE cards appears to not need this */
dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; dev_priv->scratch[0] = 0;
RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); RADEON_WRITE(RADEON_LAST_FRAME_REG, 0);
dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; dev_priv->scratch[1] = 0;
RADEON_WRITE(RADEON_LAST_DISPATCH_REG, RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0);
dev_priv->sarea_priv->last_dispatch);
dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; dev_priv->scratch[2] = 0;
RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
radeon_do_wait_for_idle(dev_priv); radeon_do_wait_for_idle(dev_priv);
...@@ -871,9 +871,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) ...@@ -871,9 +871,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
} }
} }
static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
struct drm_file *file_priv)
{ {
drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
...@@ -998,8 +1000,8 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) ...@@ -998,8 +1000,8 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
dev_priv->buffers_offset = init->buffers_offset; dev_priv->buffers_offset = init->buffers_offset;
dev_priv->gart_textures_offset = init->gart_textures_offset; dev_priv->gart_textures_offset = init->gart_textures_offset;
dev_priv->sarea = drm_getsarea(dev); master_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) { if (!master_priv->sarea) {
DRM_ERROR("could not find sarea!\n"); DRM_ERROR("could not find sarea!\n");
radeon_do_cleanup_cp(dev); radeon_do_cleanup_cp(dev);
return -EINVAL; return -EINVAL;
...@@ -1035,10 +1037,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) ...@@ -1035,10 +1037,6 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
} }
} }
dev_priv->sarea_priv =
(drm_radeon_sarea_t *) ((u8 *) dev_priv->sarea->handle +
init->sarea_priv_offset);
#if __OS_HAS_AGP #if __OS_HAS_AGP
if (dev_priv->flags & RADEON_IS_AGP) { if (dev_priv->flags & RADEON_IS_AGP) {
drm_core_ioremap(dev_priv->cp_ring, dev); drm_core_ioremap(dev_priv->cp_ring, dev);
...@@ -1329,7 +1327,7 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri ...@@ -1329,7 +1327,7 @@ int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_pri
case RADEON_INIT_CP: case RADEON_INIT_CP:
case RADEON_INIT_R200_CP: case RADEON_INIT_R200_CP:
case RADEON_INIT_R300_CP: case RADEON_INIT_R300_CP:
return radeon_do_init_cp(dev, init); return radeon_do_init_cp(dev, init, file_priv);
case RADEON_CLEANUP_CP: case RADEON_CLEANUP_CP:
return radeon_do_cleanup_cp(dev); return radeon_do_cleanup_cp(dev);
} }
...@@ -1768,6 +1766,51 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -1768,6 +1766,51 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
return ret; return ret;
} }
int radeon_master_create(struct drm_device *dev, struct drm_master *master)
{
struct drm_radeon_master_private *master_priv;
unsigned long sareapage;
int ret;
master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER);
if (!master_priv)
return -ENOMEM;
/* prebuild the SAREA */
sareapage = max(SAREA_MAX, PAGE_SIZE);
ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
&master_priv->sarea);
if (ret) {
DRM_ERROR("SAREA setup failed\n");
return ret;
}
master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea);
master_priv->sarea_priv->pfCurrentPage = 0;
master->driver_priv = master_priv;
return 0;
}
void radeon_master_destroy(struct drm_device *dev, struct drm_master *master)
{
struct drm_radeon_master_private *master_priv = master->driver_priv;
if (!master_priv)
return;
if (master_priv->sarea_priv &&
master_priv->sarea_priv->pfCurrentPage != 0)
radeon_cp_dispatch_flip(dev, master);
master_priv->sarea_priv = NULL;
if (master_priv->sarea)
drm_rmmap(dev, master_priv->sarea);
drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER);
master->driver_priv = NULL;
}
/* Create mappings for registers and framebuffer so userland doesn't necessarily /* Create mappings for registers and framebuffer so userland doesn't necessarily
* have to find them. * have to find them.
*/ */
......
...@@ -226,9 +226,13 @@ struct radeon_virt_surface { ...@@ -226,9 +226,13 @@ struct radeon_virt_surface {
#define RADEON_FLUSH_EMITED (1 < 0) #define RADEON_FLUSH_EMITED (1 < 0)
#define RADEON_PURGE_EMITED (1 < 1) #define RADEON_PURGE_EMITED (1 < 1)
struct drm_radeon_master_private {
drm_local_map_t *sarea;
drm_radeon_sarea_t *sarea_priv;
};
typedef struct drm_radeon_private { typedef struct drm_radeon_private {
drm_radeon_ring_buffer_t ring; drm_radeon_ring_buffer_t ring;
drm_radeon_sarea_t *sarea_priv;
u32 fb_location; u32 fb_location;
u32 fb_size; u32 fb_size;
...@@ -409,6 +413,9 @@ extern int radeon_driver_open(struct drm_device *dev, ...@@ -409,6 +413,9 @@ extern int radeon_driver_open(struct drm_device *dev,
extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg); unsigned long arg);
extern int radeon_master_create(struct drm_device *dev, struct drm_master *master);
extern void radeon_master_destroy(struct drm_device *dev, struct drm_master *master);
extern void radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master);
/* r300_cmdbuf.c */ /* r300_cmdbuf.c */
extern void r300_init_reg_flags(struct drm_device *dev); extern void r300_init_reg_flags(struct drm_device *dev);
...@@ -1336,7 +1343,8 @@ do { \ ...@@ -1336,7 +1343,8 @@ do { \
#define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \
do { \ do { \
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; \ struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; \
drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; \
if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \
int __ret = radeon_do_cp_idle( dev_priv ); \ int __ret = radeon_do_cp_idle( dev_priv ); \
if ( __ret ) return __ret; \ if ( __ret ) return __ret; \
......
This diff is collapsed.
...@@ -634,6 +634,9 @@ struct drm_gem_open { ...@@ -634,6 +634,9 @@ struct drm_gem_open {
#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) #define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map)
#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) #define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map)
#define DRM_IOCTL_SET_MASTER DRM_IO(0x1e)
#define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f)
#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx) #define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx)
#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx) #define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx)
#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) #define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx)
......
...@@ -238,11 +238,11 @@ struct drm_device; ...@@ -238,11 +238,11 @@ struct drm_device;
*/ */
#define LOCK_TEST_WITH_RETURN( dev, file_priv ) \ #define LOCK_TEST_WITH_RETURN( dev, file_priv ) \
do { \ do { \
if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock) || \
dev->lock.file_priv != file_priv ) { \ file_priv->master->lock.file_priv != file_priv) { \
DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
__func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ __func__, _DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock),\
dev->lock.file_priv, file_priv ); \ file_priv->master->lock.file_priv, file_priv); \
return -EINVAL; \ return -EINVAL; \
} \ } \
} while (0) } while (0)
...@@ -379,21 +379,25 @@ struct drm_buf_entry { ...@@ -379,21 +379,25 @@ struct drm_buf_entry {
/** File private data */ /** File private data */
struct drm_file { struct drm_file {
int authenticated; int authenticated;
int master;
pid_t pid; pid_t pid;
uid_t uid; uid_t uid;
drm_magic_t magic; drm_magic_t magic;
unsigned long ioctl_count; unsigned long ioctl_count;
struct list_head lhead; struct list_head lhead;
struct drm_minor *minor; struct drm_minor *minor;
int remove_auth_on_close;
unsigned long lock_count; unsigned long lock_count;
/** Mapping of mm object handles to object pointers. */ /** Mapping of mm object handles to object pointers. */
struct idr object_idr; struct idr object_idr;
/** Lock for synchronization of access to object_idr. */ /** Lock for synchronization of access to object_idr. */
spinlock_t table_lock; spinlock_t table_lock;
struct file *filp; struct file *filp;
void *driver_priv; void *driver_priv;
int is_master; /* this file private is a master for a minor */
struct drm_master *master; /* master this node is currently associated with
N.B. not always minor->master */
}; };
/** Wait queue */ /** Wait queue */
...@@ -523,6 +527,7 @@ struct drm_map_list { ...@@ -523,6 +527,7 @@ struct drm_map_list {
struct drm_hash_item hash; struct drm_hash_item hash;
struct drm_map *map; /**< mapping */ struct drm_map *map; /**< mapping */
uint64_t user_token; uint64_t user_token;
struct drm_master *master;
}; };
typedef struct drm_map drm_local_map_t; typedef struct drm_map drm_local_map_t;
...@@ -612,6 +617,30 @@ struct drm_gem_object { ...@@ -612,6 +617,30 @@ struct drm_gem_object {
void *driver_private; void *driver_private;
}; };
/* per-master structure */
struct drm_master {
struct kref refcount; /* refcount for this master */
struct list_head head; /**< each minor contains a list of masters */
struct drm_minor *minor; /**< link back to minor we are a master for */
char *unique; /**< Unique identifier: e.g., busid */
int unique_len; /**< Length of unique field */
int blocked; /**< Blocked due to VC switch? */
/** \name Authentication */
/*@{ */
struct drm_open_hash magiclist;
struct list_head magicfree;
/*@} */
struct drm_lock_data lock; /**< Information on hardware lock */
void *driver_priv; /**< Private structure for driver to use */
};
/** /**
* DRM driver structure. This structure represent the common code for * DRM driver structure. This structure represent the common code for
* a family of cards. There will one drm_device for each card present * a family of cards. There will one drm_device for each card present
...@@ -712,6 +741,10 @@ struct drm_driver { ...@@ -712,6 +741,10 @@ struct drm_driver {
void (*set_version) (struct drm_device *dev, void (*set_version) (struct drm_device *dev,
struct drm_set_version *sv); struct drm_set_version *sv);
/* Master routines */
int (*master_create)(struct drm_device *dev, struct drm_master *master);
void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
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);
...@@ -754,6 +787,8 @@ struct drm_minor { ...@@ -754,6 +787,8 @@ struct drm_minor {
struct device kdev; /**< Linux device */ struct device kdev; /**< Linux device */
struct drm_device *dev; struct drm_device *dev;
struct proc_dir_entry *dev_root; /**< proc directory entry */ struct proc_dir_entry *dev_root; /**< proc directory entry */
struct drm_master *master; /* currently active master for this node */
struct list_head master_list;
}; };
/** /**
...@@ -762,13 +797,9 @@ struct drm_minor { ...@@ -762,13 +797,9 @@ struct drm_minor {
*/ */
struct drm_device { struct drm_device {
struct list_head driver_item; /**< list of devices per driver */ struct list_head driver_item; /**< list of devices per driver */
char *unique; /**< Unique identifier: e.g., busid */
int unique_len; /**< Length of unique field */
char *devname; /**< For /proc/interrupts */ char *devname; /**< For /proc/interrupts */
int if_version; /**< Highest interface version set */ int if_version; /**< Highest interface version set */
int blocked; /**< Blocked due to VC switch? */
/** \name Locks */ /** \name Locks */
/*@{ */ /*@{ */
spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */
...@@ -791,12 +822,7 @@ struct drm_device { ...@@ -791,12 +822,7 @@ struct drm_device {
atomic_t counts[15]; atomic_t counts[15];
/*@} */ /*@} */
/** \name Authentication */
/*@{ */
struct list_head filelist; struct list_head filelist;
struct drm_open_hash magiclist; /**< magic hash table */
struct list_head magicfree;
/*@} */
/** \name Memory management */ /** \name Memory management */
/*@{ */ /*@{ */
...@@ -813,7 +839,6 @@ struct drm_device { ...@@ -813,7 +839,6 @@ struct drm_device {
struct idr ctx_idr; struct idr ctx_idr;
struct list_head vmalist; /**< List of vmas (for debugging) */ struct list_head vmalist; /**< List of vmas (for debugging) */
struct drm_lock_data lock; /**< Information on hardware lock */
/*@} */ /*@} */
/** \name DMA queues (contexts) */ /** \name DMA queues (contexts) */
...@@ -1192,6 +1217,13 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); ...@@ -1192,6 +1217,13 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
extern void drm_agp_chipset_flush(struct drm_device *dev); extern void drm_agp_chipset_flush(struct drm_device *dev);
/* Stub support (drm_stub.h) */ /* Stub support (drm_stub.h) */
extern int drm_setmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
struct drm_master *drm_master_create(struct drm_minor *minor);
extern struct drm_master *drm_master_get(struct drm_master *master);
extern void drm_master_put(struct drm_master **master);
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver); struct drm_driver *driver);
extern int drm_put_dev(struct drm_device *dev); extern int drm_put_dev(struct drm_device *dev);
......
...@@ -36,12 +36,12 @@ ...@@ -36,12 +36,12 @@
/* SAREA area needs to be at least a page */ /* SAREA area needs to be at least a page */
#if defined(__alpha__) #if defined(__alpha__)
#define SAREA_MAX 0x2000 #define SAREA_MAX 0x2000U
#elif defined(__ia64__) #elif defined(__ia64__)
#define SAREA_MAX 0x10000 /* 64kB */ #define SAREA_MAX 0x10000U /* 64kB */
#else #else
/* Intel 830M driver needs at least 8k SAREA */ /* Intel 830M driver needs at least 8k SAREA */
#define SAREA_MAX 0x2000 #define SAREA_MAX 0x2000U
#endif #endif
/** Maximum number of drawables in the SAREA */ /** Maximum number of drawables in the SAREA */
......
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