From 36837fc9b8c51f3aae0783d38b63d87ef4d77ad2 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 7 Nov 2008 14:17:34 -0800 Subject: [PATCH] DRM: rework master design Need description from airlied here. --- drivers/gpu/drm/drm_auth.c | 29 +++--- drivers/gpu/drm/drm_bufs.c | 20 +++- drivers/gpu/drm/drm_context.c | 10 +- drivers/gpu/drm/drm_drv.c | 33 +----- drivers/gpu/drm/drm_fops.c | 201 ++++++++++++++++++++------------- drivers/gpu/drm/drm_ioctl.c | 57 +++++----- drivers/gpu/drm/drm_lock.c | 42 ++++--- drivers/gpu/drm/drm_proc.c | 8 +- drivers/gpu/drm/drm_stub.c | 105 ++++++++++++++++- drivers/gpu/drm/i915/i915_dma.c | 81 ++++++++----- drivers/gpu/drm/i915/i915_drv.c | 2 + drivers/gpu/drm/i915/i915_drv.h | 10 ++- drivers/gpu/drm/i915/i915_irq.c | 26 ++--- drivers/gpu/drm/i915/i915_mem.c | 3 +- drivers/gpu/drm/radeon/r300_cmdbuf.c | 11 +- drivers/gpu/drm/radeon/radeon_cp.c | 73 ++++++++++--- drivers/gpu/drm/radeon/radeon_drv.h | 15 ++- drivers/gpu/drm/radeon/radeon_state.c | 166 +++++++++++++++------------ include/drm/drm.h | 3 + include/drm/drmP.h | 69 +++++++++--- 20 files changed, 614 insertions(+), 350 deletions(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index a734627..ca7a9ef 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -45,14 +45,15 @@ * the one with matching magic number, while holding the drm_device::struct_mutex * 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_magic_entry *pt; struct drm_hash_item *hash; + struct drm_device *dev = master->minor->dev; 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); retval = pt->priv; } @@ -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 * 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) { struct drm_magic_entry *entry; - + struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", 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, return -ENOMEM; memset(entry, 0, sizeof(*entry)); entry->priv = priv; - entry->hash_item.key = (unsigned long)magic; mutex_lock(&dev->struct_mutex); - drm_ht_insert_item(&dev->magiclist, &entry->hash_item); - list_add_tail(&entry->head, &dev->magicfree); + drm_ht_insert_item(&master->magiclist, &entry->hash_item); + list_add_tail(&entry->head, &master->magicfree); mutex_unlock(&dev->struct_mutex); return 0; @@ -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 * 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_hash_item *hash; + struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", magic); 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); return -EINVAL; } 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); mutex_unlock(&dev->struct_mutex); @@ -153,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) ++sequence; /* reserve 0 */ auth->magic = sequence++; spin_unlock(&lock); - } while (drm_find_file(dev, auth->magic)); + } while (drm_find_file(file_priv->master, 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); @@ -181,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file; 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; - drm_remove_magic(dev, auth->magic); + drm_remove_magic(file_priv->master, auth->magic); return 0; } return -EINVAL; diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 9916366..7fb690b 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -54,9 +54,9 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, { struct drm_map_list *entry; 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) || - (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) { + ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) { return entry; } } @@ -210,12 +210,12 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, map->offset = (unsigned long)map->handle; if (map->flags & _DRM_CONTAINS_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); drm_free(map, sizeof(*map), DRM_MEM_MAPS); 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; case _DRM_AGP: { @@ -322,6 +322,7 @@ static int drm_addmap_core(struct drm_device * dev, unsigned int offset, list->user_token = list->hash.key << PAGE_SHIFT; mutex_unlock(&dev->struct_mutex); + list->master = dev->primary->master; *maplist = list; return 0; } @@ -348,7 +349,7 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data, struct drm_map_list *maplist; 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; err = drm_addmap_core(dev, map->offset, map->size, map->type, @@ -383,10 +384,12 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) struct drm_map_list *r_list = NULL, *list_t; drm_dma_handle_t dmah; int found = 0; + struct drm_master *master; /* Find the list entry for the map and remove it */ list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { if (r_list->map == map) { + master = r_list->master; list_del(&r_list->head); drm_ht_remove_key(&dev->map_hash, r_list->user_token >> PAGE_SHIFT); @@ -412,6 +415,13 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map) break; case _DRM_SHM: 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; case _DRM_AGP: case _DRM_SCATTER_GATHER: diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index d505f69..809ec0f 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -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 * 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_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"); } @@ -420,7 +421,7 @@ int drm_newctx(struct drm_device *dev, void *data, struct drm_ctx *ctx = data; DRM_DEBUG("%d\n", ctx->handle); - drm_context_switch_complete(dev, ctx->handle); + drm_context_switch_complete(dev, file_priv, ctx->handle); return 0; } @@ -442,9 +443,6 @@ int drm_rmctx(struct drm_device *dev, void *data, struct drm_ctx *ctx = data; 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 (dev->driver->context_dtor) dev->driver->context_dtor(dev, ctx->handle); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index aad8d76..d44b0c3 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -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_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_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), @@ -138,8 +141,6 @@ static struct drm_ioctl_desc drm_ioctls[] = { */ 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; int i; @@ -149,12 +150,6 @@ int drm_lastclose(struct drm_device * dev) dev->driver->lastclose(dev); 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) drm_irq_uninstall(dev); @@ -164,16 +159,6 @@ int drm_lastclose(struct drm_device * dev) drm_drawable_free_all(dev); 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 */ if (drm_core_has_AGP(dev) && dev->agp) { struct drm_agp_mem *entry, *tempe; @@ -205,13 +190,6 @@ int drm_lastclose(struct drm_device * dev) 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) { for (i = 0; i < dev->queue_count; i++) { if (dev->queuelist[i]) { @@ -231,11 +209,6 @@ int drm_lastclose(struct drm_device * dev) if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) 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); - } dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index ef20428..3a6c439 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -44,10 +44,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp, static int drm_setup(struct drm_device * dev) { - drm_local_map_t *map; int i; int ret; - u32 sareapage; if (dev->driver->firstopen) { ret = dev->driver->firstopen(dev); @@ -55,14 +53,6 @@ static int drm_setup(struct drm_device * dev) 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->vma_count, 0); dev->buf_use = 0; @@ -77,16 +67,12 @@ static int drm_setup(struct drm_device * dev) for (i = 0; i < ARRAY_SIZE(dev->counts); i++) atomic_set(&dev->counts[i], 0); - drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); - INIT_LIST_HEAD(&dev->magicfree); - dev->sigdata.lock = NULL; - init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; dev->queue_reserved = 0; dev->queue_slots = 0; dev->queuelist = NULL; - dev->irq_enabled = 0; dev->context_flag = 0; dev->interrupt_flag = 0; dev->dma_flag = 0; @@ -275,10 +261,42 @@ static int drm_open_helper(struct inode *inode, struct file *filp, goto out_free; } + + /* if there is no current master make this fd it */ mutex_lock(&dev->struct_mutex); - if (list_empty(&dev->filelist)) - priv->master = 1; + if (!priv->minor->master) { + /* 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); mutex_unlock(&dev->struct_mutex); @@ -324,6 +342,74 @@ int drm_fasync(int fd, struct file *filp, int on) } EXPORT_SYMBOL(drm_fasync); +/* + * Reclaim locked buffers; note that this may be a bad idea if the current + * context doesn't have the hw lock... + */ +static void drm_reclaim_locked_buffers(struct drm_device *dev, struct file *f) +{ + struct drm_file *file_priv = f->private_data; + + if (drm_i_have_hw_lock(dev, file_priv)) { + dev->driver->reclaim_buffers_locked(dev, file_priv); + } else { + unsigned long _end = jiffies + 3 * DRM_HZ; + int locked = 0; + + drm_idlelock_take(&file_priv->master->lock); + + /* + * Wait for a while. + */ + do { + spin_lock_bh(&file_priv->master->lock.spinlock); + locked = file_priv->master->lock.idle_has_lock; + spin_unlock_bh(&file_priv->master->lock.spinlock); + if (locked) + break; + schedule(); + } while (!time_after_eq(jiffies, _end)); + + if (!locked) { + DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" + "\tdriver to use reclaim_buffers_idlelocked() instead.\n" + "\tI will go on reclaiming the buffers anyway.\n"); + } + + dev->driver->reclaim_buffers_locked(dev, file_priv); + drm_idlelock_release(&file_priv->master->lock); + } +} + +static void drm_master_release(struct drm_device *dev, struct file *filp) +{ + struct drm_file *file_priv = filp->private_data; + + if (dev->driver->reclaim_buffers_locked && + file_priv->master->lock.hw_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)) { + DRM_DEBUG("File %p released, freeing lock for context %d\n", + filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); + drm_lock_free(&file_priv->master->lock, + _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); + } + + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && + !dev->driver->reclaim_buffers_locked) { + dev->driver->reclaim_buffers(dev, file_priv); + } +} + /** * Release file. * @@ -358,60 +444,9 @@ int drm_release(struct inode *inode, struct file *filp) (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)) { - dev->driver->reclaim_buffers_locked(dev, file_priv); - } else { - unsigned long endtime = jiffies + 3 * DRM_HZ; - int locked = 0; - - drm_idlelock_take(&dev->lock); - - /* - * Wait for a while. - */ - - do{ - spin_lock_bh(&dev->lock.spinlock); - locked = dev->lock.idle_has_lock; - spin_unlock_bh(&dev->lock.spinlock); - if (locked) - break; - schedule(); - } while (!time_after_eq(jiffies, endtime)); - - if (!locked) { - DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n" - "\tdriver to use reclaim_buffers_idlelocked() instead.\n" - "\tI will go on reclaiming the buffers anyway.\n"); - } - - dev->driver->reclaim_buffers_locked(dev, file_priv); - drm_idlelock_release(&dev->lock); - } - } - - if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) { - - drm_idlelock_take(&dev->lock); - dev->driver->reclaim_buffers_idlelocked(dev, file_priv); - drm_idlelock_release(&dev->lock); - - } - - if (drm_i_have_hw_lock(dev, file_priv)) { - DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - - drm_lock_free(&dev->lock, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - } - - - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && - !dev->driver->reclaim_buffers_locked) { - dev->driver->reclaim_buffers(dev, file_priv); - } + /* 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) drm_gem_release(dev, file_priv); @@ -438,12 +473,24 @@ int drm_release(struct inode *inode, struct file *filp) mutex_unlock(&dev->ctxlist_mutex); mutex_lock(&dev->struct_mutex); - if (file_priv->remove_auth_on_close == 1) { + + 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; + } - list_for_each_entry(temp, &dev->filelist, lhead) - 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); mutex_unlock(&dev->struct_mutex); @@ -458,9 +505,9 @@ int drm_release(struct inode *inode, struct file *filp) atomic_inc(&dev->counts[_DRM_STAT_CLOSES]); spin_lock(&dev->count_lock); if (!--dev->open_count) { - if (atomic_read(&dev->ioctl_count) || dev->blocked) { - DRM_ERROR("Device busy: %d %d\n", - atomic_read(&dev->ioctl_count), dev->blocked); + if (atomic_read(&dev->ioctl_count)) { + DRM_ERROR("Device busy: %d\n", + atomic_read(&dev->ioctl_count)); spin_unlock(&dev->count_lock); unlock_kernel(); return -EBUSY; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 16829fb..e35126a 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; + struct drm_master *master = file_priv->master; - if (u->unique_len >= dev->unique_len) { - if (copy_to_user(u->unique, dev->unique, dev->unique_len)) + if (u->unique_len >= master->unique_len) { + if (copy_to_user(u->unique, master->unique, master->unique_len)) return -EFAULT; } - u->unique_len = dev->unique_len; + u->unique_len = master->unique_len; return 0; } @@ -81,36 +82,37 @@ int drm_setunique(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_unique *u = data; + struct drm_master *master = file_priv->master; int domain, bus, slot, func, ret; - if (dev->unique_len || dev->unique) + if (master->unique_len || master->unique) return -EBUSY; if (!u->unique_len || u->unique_len > 1024) return -EINVAL; - dev->unique_len = u->unique_len; - dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); - if (!dev->unique) + master->unique_len = u->unique_len; + master->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER); + if (!master->unique) 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; - dev->unique[dev->unique_len] = '\0'; + master->unique[master->unique_len] = '\0'; dev->devname = 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) return -ENOMEM; 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 * 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) return -EINVAL; domain = bus >> 8; @@ -125,34 +127,35 @@ int drm_setunique(struct drm_device *dev, void *data, 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; - if (dev->unique != NULL) - return 0; + if (master->unique != NULL) + return -EBUSY; - dev->unique_len = 40; - dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); - if (dev->unique == NULL) + master->unique_len = 40; + master->unique = drm_alloc(master->unique_len + 1, DRM_MEM_DRIVER); + if (master->unique == NULL) return -ENOMEM; - len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", - drm_get_pci_domain(dev), dev->pdev->bus->number, + len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d", + drm_get_pci_domain(dev), + dev->pdev->bus->number, PCI_SLOT(dev->pdev->devfn), PCI_FUNC(dev->pdev->devfn)); - - if (len > dev->unique_len) - DRM_ERROR("Unique buffer overflowed\n"); + if (len > master->unique_len) + DRM_ERROR("buffer overflow"); 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); if (dev->devname == NULL) return -ENOMEM; sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, - dev->unique); + master->unique); return 0; } @@ -276,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data, for (i = 0; i < dev->counters; i++) { if (dev->types[i] == _DRM_STAT_LOCK) 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 stats->data[i].value = atomic_read(&dev->counts[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 /* * Version 1.1 includes tying of DRM to specific device */ - drm_set_busid(dev); + drm_set_busid(dev, file_priv); } } diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index 1cfa720..c773006 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) { DECLARE_WAITQUEUE(entry, current); struct drm_lock *lock = data; + struct drm_master *master = file_priv->master; int ret = 0; ++file_priv->lock_count; @@ -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", 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 (lock->context < 0) return -EINVAL; - add_wait_queue(&dev->lock.lock_queue, &entry); - spin_lock_bh(&dev->lock.spinlock); - dev->lock.user_waiters++; - spin_unlock_bh(&dev->lock.spinlock); + add_wait_queue(&master->lock.lock_queue, &entry); + spin_lock_bh(&master->lock.spinlock); + master->lock.user_waiters++; + spin_unlock_bh(&master->lock.spinlock); + for (;;) { __set_current_state(TASK_INTERRUPTIBLE); - if (!dev->lock.hw_lock) { + if (!master->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; break; } - if (drm_lock_take(&dev->lock, lock->context)) { - dev->lock.file_priv = file_priv; - dev->lock.lock_time = jiffies; + if (drm_lock_take(&master->lock, lock->context)) { + master->lock.file_priv = file_priv; + master->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); break; /* Got lock */ } @@ -95,11 +97,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) break; } } - spin_lock_bh(&dev->lock.spinlock); - dev->lock.user_waiters--; - spin_unlock_bh(&dev->lock.spinlock); + spin_lock_bh(&master->lock.spinlock); + master->lock.user_waiters--; + spin_unlock_bh(&master->lock.spinlock); __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, ret ? "interrupted" : "has lock"); @@ -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 * really probably not the correct answer but lets us debug xkb * xserver for now */ - if (!file_priv->master) { + if (!file_priv->is_master) { sigemptyset(&dev->sigmask); sigaddset(&dev->sigmask, SIGSTOP); sigaddset(&dev->sigmask, SIGTSTP); sigaddset(&dev->sigmask, SIGTTIN); sigaddset(&dev->sigmask, SIGTTOU); 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); } @@ -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) { struct drm_lock *lock = data; + struct drm_master *master = file_priv->master; if (lock->context == DRM_KERNEL_CONTEXT) { 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) if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - if (drm_lock_free(&dev->lock,lock->context)) { + if (drm_lock_free(&master->lock,lock->context)) { /* FIXME: Should really bail out here. */ } } @@ -379,9 +382,10 @@ EXPORT_SYMBOL(drm_idlelock_release); int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) { - return (file_priv->lock_count && dev->lock.hw_lock && - _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.file_priv == file_priv); + struct drm_master *master = file_priv->master; + return (file_priv->lock_count && master->lock.hw_lock && + _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && + master->lock.file_priv == file_priv); } EXPORT_SYMBOL(drm_i_have_hw_lock); diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index ae73b7f..7dbaa1a 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c @@ -195,6 +195,7 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { struct drm_minor *minor = (struct drm_minor *) data; + struct drm_master *master = minor->master; struct drm_device *dev = minor->dev; int len = 0; @@ -203,13 +204,16 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, return 0; } + if (!master) + return 0; + *start = &buf[offset]; *eof = 0; - if (dev->unique) { + if (master->unique) { DRM_PROC_PRINT("%s %s %s\n", dev->driver->pci_driver.name, - pci_name(dev->pdev), dev->unique); + pci_name(dev->pdev), master->unique); } else { DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name, pci_name(dev->pdev)); diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 66c96ec..e3d6b4a 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -79,6 +79,104 @@ again: 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; /* SHM removed */ + 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, const struct pci_device_id *ent, struct drm_driver *driver) @@ -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->drw_lock); - spin_lock_init(&dev->lock.spinlock); init_timer(&dev->timer); mutex_init(&dev->struct_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 new_minor->device = MKDEV(DRM_MAJOR, minor_id); new_minor->dev = dev; new_minor->index = minor_id; + INIT_LIST_HEAD(&new_minor->master_list); idr_replace(&drm_minors_idr, new_minor, minor_id); @@ -297,11 +395,6 @@ int drm_put_dev(struct drm_device * dev) { 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) { drm_free(dev->devname, strlen(dev->devname) + 1, DRM_MEM_DRIVER); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7651ebc..fcae091 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -39,6 +39,7 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) { 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); u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; u32 last_acthd = I915_READ(acthd_reg); @@ -55,8 +56,8 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) if (ring->space >= n) return 0; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + if (master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; if (ring->head != last_head) i = 0; @@ -121,6 +122,7 @@ static void i915_free_hws(struct drm_device *dev) void i915_kernel_lost_context(struct drm_device * dev) { 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); ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; @@ -129,8 +131,12 @@ void i915_kernel_lost_context(struct drm_device * dev) if (ring->space < 0) ring->space += ring->Size; - if (ring->head == ring->tail && dev_priv->sarea_priv) - dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; + if (!dev->primary->master) + 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) @@ -154,25 +160,13 @@ static int i915_dma_cleanup(struct drm_device * dev) if (I915_NEED_GFX_HWS(dev)) i915_free_hws(dev); - dev_priv->sarea = NULL; - dev_priv->sarea_priv = NULL; - return 0; } static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) { drm_i915_private_t *dev_priv = dev->dev_private; - - 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); + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; if (init->ring_size != 0) { if (dev_priv->ring.ring_obj != NULL) { @@ -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->front_offset = init->front_offset; 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. */ @@ -222,11 +217,6 @@ static int i915_dma_resume(struct drm_device * dev) 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) { DRM_ERROR("can not ioremap virtual address for" " ring buffer\n"); @@ -435,13 +425,14 @@ i915_emit_box(struct drm_device *dev, static void i915_emit_breadcrumb(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; RING_LOCALS; dev_priv->counter++; if (dev_priv->counter > 0x7FFFFFFFUL) dev_priv->counter = 0; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_enqueue = dev_priv->counter; BEGIN_LP_RING(4); OUT_RING(MI_STORE_DWORD_INDEX); @@ -537,15 +528,17 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, static int i915_dispatch_flip(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = + dev->primary->master->driver_priv; RING_LOCALS; - if (!dev_priv->sarea_priv) + if (!master_priv->sarea_priv) return -EINVAL; DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", __func__, dev_priv->current_page, - dev_priv->sarea_priv->pf_current_page); + master_priv->sarea_priv->pf_current_page); i915_kernel_lost_context(dev); @@ -572,7 +565,7 @@ static int i915_dispatch_flip(struct drm_device * dev) OUT_RING(0); 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); OUT_RING(MI_STORE_DWORD_INDEX); @@ -581,7 +574,7 @@ static int i915_dispatch_flip(struct drm_device * dev) OUT_RING(0); 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; } @@ -611,9 +604,10 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { 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; u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) - dev_priv->sarea_priv; + master_priv->sarea_priv; drm_i915_batchbuffer_t *batch = data; int ret; @@ -645,9 +639,10 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv) { 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; u32 *hw_status = dev_priv->hw_status_page; drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) - dev_priv->sarea_priv; + master_priv->sarea_priv; drm_i915_cmdbuffer_t *cmdbuf = data; int ret; @@ -804,6 +799,30 @@ static int i915_set_status_page(struct drm_device *dev, void *data, 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) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1c87509..e0d996e 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -111,6 +111,8 @@ static struct drm_driver driver = { .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_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_cleanup = i915_gem_proc_cleanup, .gem_init_object = i915_gem_init_object, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3a7e2bb..a283506 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -107,13 +107,16 @@ struct drm_i915_fence_reg { struct drm_gem_object *obj; }; +struct drm_i915_master_private { + drm_local_map_t *sarea; + struct _drm_i915_sarea *sarea_priv; +}; + typedef struct drm_i915_private { struct drm_device *dev; void __iomem *regs; - drm_local_map_t *sarea; - drm_i915_sarea_t *sarea_priv; drm_i915_ring_buffer_t ring; drm_dma_handle_t *status_page_dmah; @@ -432,6 +435,9 @@ struct drm_i915_file_private { extern struct drm_ioctl_desc i915_ioctls[]; 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 */ extern void i915_kernel_lost_context(struct drm_device * dev); extern int i915_driver_load(struct drm_device *, unsigned long flags); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a75345a..d31665b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -121,6 +121,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; 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; u32 iir; u32 pipea_stats, pipeb_stats; int vblank = 0; @@ -182,9 +183,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_WRITE(IMR, dev_priv->irq_mask_reg); (void) I915_READ(IIR); /* Flush posted writes */ - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); if (iir & I915_USER_INTERRUPT) { dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); @@ -200,6 +200,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) static int i915_emit_irq(struct drm_device * dev) { drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; RING_LOCALS; i915_kernel_lost_context(dev); @@ -209,8 +210,8 @@ static int i915_emit_irq(struct drm_device * dev) dev_priv->counter++; if (dev_priv->counter > 0x7FFFFFFFUL) dev_priv->counter = 1; - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter; + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_enqueue = dev_priv->counter; BEGIN_LP_RING(6); OUT_RING(MI_STORE_DWORD_INDEX); @@ -250,21 +251,20 @@ void i915_user_irq_put(struct drm_device *dev) 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; + struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; int ret = 0; DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, READ_BREADCRUMB(dev_priv)); if (READ_BREADCRUMB(dev_priv) >= irq_nr) { - if (dev_priv->sarea_priv) { - dev_priv->sarea_priv->last_dispatch = - READ_BREADCRUMB(dev_priv); - } + if (master_priv->sarea_priv) + master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); return 0; } - if (dev_priv->sarea_priv) - dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; + if (master_priv->sarea_priv) + master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; i915_user_irq_get(dev); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, @@ -276,10 +276,6 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) 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; } diff --git a/drivers/gpu/drm/i915/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c index 6126a60..96e2719 100644 --- a/drivers/gpu/drm/i915/i915_mem.c +++ b/drivers/gpu/drm/i915/i915_mem.c @@ -46,7 +46,8 @@ 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_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; unsigned shift, nr; unsigned start; diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c index 4b27d9a..bbbe5b1 100644 --- a/drivers/gpu/drm/radeon/r300_cmdbuf.c +++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c @@ -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 * 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; + 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->used = 0; } @@ -1027,6 +1027,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, drm_radeon_kcmd_buffer_t *cmdbuf) { 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_buf *buf = NULL; int emit_dispatch_age = 0; @@ -1134,7 +1135,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, } emit_dispatch_age = 1; - r300_discard_buffer(dev, buf); + r300_discard_buffer(dev, file_priv->master, buf); break; case R300_CMD_WAIT: @@ -1189,7 +1190,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev, /* Emit the vertex buffer age */ BEGIN_RING(2); - RADEON_DISPATCH_AGE(dev_priv->sarea_priv->last_dispatch); + RADEON_DISPATCH_AGE(master_priv->sarea_priv->last_dispatch); ADVANCE_RING(); } diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 0738948..b63c5a8 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -31,6 +31,7 @@ #include "drmP.h" #include "drm.h" +#include "drm_sarea.h" #include "radeon_drm.h" #include "radeon_drv.h" #include "r300_reg.h" @@ -667,15 +668,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev, RADEON_WRITE(RADEON_BUS_CNTL, tmp); } /* PCIE cards appears to not need this */ - dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; - RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); + dev_priv->scratch[0] = 0; + RADEON_WRITE(RADEON_LAST_FRAME_REG, 0); - dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; - RADEON_WRITE(RADEON_LAST_DISPATCH_REG, - dev_priv->sarea_priv->last_dispatch); + dev_priv->scratch[1] = 0; + RADEON_WRITE(RADEON_LAST_DISPATCH_REG, 0); - dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; - RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); + dev_priv->scratch[2] = 0; + RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0); radeon_do_wait_for_idle(dev_priv); @@ -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; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; DRM_DEBUG("\n"); @@ -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->gart_textures_offset = init->gart_textures_offset; - dev_priv->sarea = drm_getsarea(dev); - if (!dev_priv->sarea) { + master_priv->sarea = drm_getsarea(dev); + if (!master_priv->sarea) { DRM_ERROR("could not find sarea!\n"); radeon_do_cleanup_cp(dev); return -EINVAL; @@ -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 (dev_priv->flags & RADEON_IS_AGP) { 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 case RADEON_INIT_CP: case RADEON_INIT_R200_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: return radeon_do_cleanup_cp(dev); } @@ -1756,6 +1754,51 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) 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 * have to find them. */ diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 02f5575..6275abd 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -226,9 +226,13 @@ struct radeon_virt_surface { #define RADEON_FLUSH_EMITED (1 < 0) #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 { drm_radeon_ring_buffer_t ring; - drm_radeon_sarea_t *sarea_priv; u32 fb_location; u32 fb_size; @@ -286,7 +290,6 @@ typedef struct drm_radeon_private { unsigned long buffers_offset; unsigned long gart_textures_offset; - drm_local_map_t *sarea; drm_local_map_t *mmio; drm_local_map_t *cp_ring; drm_local_map_t *ring_rptr; @@ -410,6 +413,9 @@ extern int radeon_driver_open(struct drm_device *dev, extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd, 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 */ extern void r300_init_reg_flags(struct drm_device *dev); @@ -1336,8 +1342,9 @@ do { \ } while (0) #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ -do { \ - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; \ +do { \ + 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 ) { \ int __ret = radeon_do_cp_idle( dev_priv ); \ if ( __ret ) return __ret; \ diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 5d7153f..8c184a9 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -742,13 +742,14 @@ static struct { */ static void radeon_clear_box(drm_radeon_private_t * dev_priv, + struct drm_radeon_master_private *master_priv, int x, int y, int w, int h, int r, int g, int b) { u32 color; RING_LOCALS; - x += dev_priv->sarea_priv->boxes[0].x1; - y += dev_priv->sarea_priv->boxes[0].y1; + x += master_priv->sarea_priv->boxes[0].x1; + y += master_priv->sarea_priv->boxes[0].y1; switch (dev_priv->color_fmt) { case RADEON_COLOR_FORMAT_RGB565: @@ -776,7 +777,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, RADEON_GMC_SRC_DATATYPE_COLOR | RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS); - if (dev_priv->sarea_priv->pfCurrentPage == 1) { + if (master_priv->sarea_priv->pfCurrentPage == 1) { OUT_RING(dev_priv->front_pitch_offset); } else { OUT_RING(dev_priv->back_pitch_offset); @@ -790,7 +791,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv, ADVANCE_RING(); } -static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) +static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv, struct drm_radeon_master_private *master_priv) { /* Collapse various things into a wait flag -- trying to * guess if userspase slept -- better just to have them tell us. @@ -807,12 +808,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) /* Purple box for page flipping */ if (dev_priv->stats.boxes & RADEON_BOX_FLIP) - radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255); + radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255); /* Red box if we have to wait for idle at any point */ if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE) - radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0); + radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0); /* Blue box: lost context? */ @@ -820,12 +821,12 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) /* Yellow box for texture swaps */ if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD) - radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0); + radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0); /* Green box if hardware never idles (as far as we can tell) */ if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) - radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0); + radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0); /* Draw bars indicating number of buffers allocated * (not a great measure, easily confused) @@ -834,7 +835,7 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) if (dev_priv->stats.requested_bufs > 100) dev_priv->stats.requested_bufs = 100; - radeon_clear_box(dev_priv, 4, 16, + radeon_clear_box(dev_priv, master_priv, 4, 16, dev_priv->stats.requested_bufs, 4, 196, 128, 128); } @@ -848,11 +849,13 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv) */ static void radeon_cp_dispatch_clear(struct drm_device * dev, + struct drm_master *master, drm_radeon_clear_t * clear, drm_radeon_clear_rect_t * depth_boxes) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear; int nbox = sarea_priv->nbox; struct drm_clip_rect *pbox = sarea_priv->boxes; @@ -864,7 +867,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, dev_priv->stats.clears++; - if (dev_priv->sarea_priv->pfCurrentPage == 1) { + if (sarea_priv->pfCurrentPage == 1) { unsigned int tmp = flags; flags &= ~(RADEON_FRONT | RADEON_BACK); @@ -890,7 +893,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { int x = pbox[i].x1; @@ -967,7 +970,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. * we haven't touched any "normal" state - still need this? */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; if ((dev_priv->flags & RADEON_HAS_HIERZ) && (flags & RADEON_USE_HIERZ)) { @@ -1214,7 +1217,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { @@ -1285,7 +1288,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, /* Make sure we restore the 3D state next time. */ - dev_priv->sarea_priv->ctx_owner = 0; + sarea_priv->ctx_owner = 0; for (i = 0; i < nbox; i++) { @@ -1328,20 +1331,21 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, * wait on this value before performing the clear ioctl. We * need this because the card's so damned fast... */ - dev_priv->sarea_priv->last_clear++; + sarea_priv->last_clear++; BEGIN_RING(4); - RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear); + RADEON_CLEAR_AGE(sarea_priv->last_clear); RADEON_WAIT_UNTIL_IDLE(); ADVANCE_RING(); } -static void radeon_cp_dispatch_swap(struct drm_device * dev) +static void radeon_cp_dispatch_swap(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int nbox = sarea_priv->nbox; struct drm_clip_rect *pbox = sarea_priv->boxes; int i; @@ -1351,7 +1355,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) /* Do some trivial performance monitoring... */ if (dev_priv->do_boxes) - radeon_cp_performance_boxes(dev_priv); + radeon_cp_performance_boxes(dev_priv, master_priv); /* Wait for the 3D stream to idle before dispatching the bitblt. * This will prevent data corruption between the two streams. @@ -1385,7 +1389,7 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) /* Make this work even if front & back are flipped: */ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); - if (dev_priv->sarea_priv->pfCurrentPage == 0) { + if (sarea_priv->pfCurrentPage == 0) { OUT_RING(dev_priv->back_pitch_offset); OUT_RING(dev_priv->front_pitch_offset); } else { @@ -1405,31 +1409,32 @@ static void radeon_cp_dispatch_swap(struct drm_device * dev) * throttle the framerate by waiting for this value before * performing the swapbuffer ioctl. */ - dev_priv->sarea_priv->last_frame++; + sarea_priv->last_frame++; BEGIN_RING(4); - RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); + RADEON_FRAME_AGE(sarea_priv->last_frame); RADEON_WAIT_UNTIL_2D_IDLE(); ADVANCE_RING(); } -static void radeon_cp_dispatch_flip(struct drm_device * dev) +void radeon_cp_dispatch_flip(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; - struct drm_sarea *sarea = (struct drm_sarea *) dev_priv->sarea->handle; - int offset = (dev_priv->sarea_priv->pfCurrentPage == 1) + struct drm_radeon_master_private *master_priv = master->driver_priv; + struct drm_sarea *sarea = (struct drm_sarea *) master_priv->sarea->handle; + int offset = (master_priv->sarea_priv->pfCurrentPage == 1) ? dev_priv->front_offset : dev_priv->back_offset; RING_LOCALS; DRM_DEBUG("pfCurrentPage=%d\n", - dev_priv->sarea_priv->pfCurrentPage); + master_priv->sarea_priv->pfCurrentPage); /* Do some trivial performance monitoring... */ if (dev_priv->do_boxes) { dev_priv->stats.boxes |= RADEON_BOX_FLIP; - radeon_cp_performance_boxes(dev_priv); + radeon_cp_performance_boxes(dev_priv, master_priv); } /* Update the frame offsets for both CRTCs @@ -1441,7 +1446,7 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) ((sarea->frame.y * dev_priv->front_pitch + sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) + offset); - OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base + OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base + offset); ADVANCE_RING(); @@ -1450,13 +1455,13 @@ static void radeon_cp_dispatch_flip(struct drm_device * dev) * throttle the framerate by waiting for this value before * performing the swapbuffer ioctl. */ - dev_priv->sarea_priv->last_frame++; - dev_priv->sarea_priv->pfCurrentPage = - 1 - dev_priv->sarea_priv->pfCurrentPage; + master_priv->sarea_priv->last_frame++; + master_priv->sarea_priv->pfCurrentPage = + 1 - master_priv->sarea_priv->pfCurrentPage; BEGIN_RING(2); - RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame); + RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame); ADVANCE_RING(); } @@ -1494,11 +1499,13 @@ typedef struct { } drm_radeon_tcl_prim_t; static void radeon_cp_dispatch_vertex(struct drm_device * dev, + struct drm_file *file_priv, struct drm_buf * buf, drm_radeon_tcl_prim_t * prim) { drm_radeon_private_t *dev_priv = dev->dev_private; - 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; int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; int numverts = (int)prim->numverts; int nbox = sarea_priv->nbox; @@ -1539,13 +1546,14 @@ static void radeon_cp_dispatch_vertex(struct drm_device * dev, } while (i < nbox); } -static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_buf * buf) +static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_master *master, struct drm_buf * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; drm_radeon_buf_priv_t *buf_priv = buf->dev_private; RING_LOCALS; - buf_priv->age = ++dev_priv->sarea_priv->last_dispatch; + buf_priv->age = ++master_priv->sarea_priv->last_dispatch; /* Emit the vertex buffer age */ BEGIN_RING(2); @@ -1590,12 +1598,14 @@ static void radeon_cp_dispatch_indirect(struct drm_device * dev, } } -static void radeon_cp_dispatch_indices(struct drm_device * dev, +static void radeon_cp_dispatch_indices(struct drm_device *dev, + struct drm_master *master, struct drm_buf * elt_buf, drm_radeon_tcl_prim_t * prim) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + struct drm_radeon_master_private *master_priv = master->driver_priv; + drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv; int offset = dev_priv->gart_buffers_offset + prim->offset; u32 *data; int dwords; @@ -1870,7 +1880,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev, ADVANCE_RING(); COMMIT_RING(); - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); /* Update the input parameters for next time */ image->y += height; @@ -2110,7 +2120,8 @@ static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_fi static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - 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; drm_radeon_clear_t *clear = data; drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; DRM_DEBUG("\n"); @@ -2126,7 +2137,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * sarea_priv->nbox * sizeof(depth_boxes[0]))) return -EFAULT; - radeon_cp_dispatch_clear(dev, clear, depth_boxes); + radeon_cp_dispatch_clear(dev, file_priv->master, clear, depth_boxes); COMMIT_RING(); return 0; @@ -2134,9 +2145,10 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file * /* Not sure why this isn't set all the time: */ -static int radeon_do_init_pageflip(struct drm_device * dev) +static int radeon_do_init_pageflip(struct drm_device * dev, struct drm_master *master) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = master->driver_priv; RING_LOCALS; DRM_DEBUG("\n"); @@ -2153,8 +2165,8 @@ static int radeon_do_init_pageflip(struct drm_device * dev) dev_priv->page_flipping = 1; - if (dev_priv->sarea_priv->pfCurrentPage != 1) - dev_priv->sarea_priv->pfCurrentPage = 0; + if (master_priv->sarea_priv->pfCurrentPage != 1) + master_priv->sarea_priv->pfCurrentPage = 0; return 0; } @@ -2172,9 +2184,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f RING_SPACE_TEST_WITH_RETURN(dev_priv); if (!dev_priv->page_flipping) - radeon_do_init_pageflip(dev); + radeon_do_init_pageflip(dev, file_priv->master); - radeon_cp_dispatch_flip(dev); + radeon_cp_dispatch_flip(dev, file_priv->master); COMMIT_RING(); return 0; @@ -2183,7 +2195,9 @@ static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - 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; + DRM_DEBUG("\n"); LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -2193,8 +2207,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - radeon_cp_dispatch_swap(dev); - dev_priv->sarea_priv->ctx_owner = 0; + radeon_cp_dispatch_swap(dev, file_priv->master); + sarea_priv->ctx_owner = 0; COMMIT_RING(); return 0; @@ -2203,7 +2217,8 @@ static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *f static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - 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; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_radeon_vertex_t *vertex = data; @@ -2211,6 +2226,8 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file LOCK_TEST_WITH_RETURN(dev, file_priv); + sarea_priv = master_priv->sarea_priv; + DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); @@ -2263,13 +2280,13 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file prim.finish = vertex->count; /* unused */ prim.prim = vertex->prim; prim.numverts = vertex->count; - prim.vc_format = dev_priv->sarea_priv->vc_format; + prim.vc_format = sarea_priv->vc_format; - radeon_cp_dispatch_vertex(dev, buf, &prim); + radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim); } if (vertex->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2279,7 +2296,8 @@ static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - 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; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_radeon_indices_t *elts = data; @@ -2288,6 +2306,8 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file LOCK_TEST_WITH_RETURN(dev, file_priv); + sarea_priv = master_priv->sarea_priv; + DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n", DRM_CURRENTPID, elts->idx, elts->start, elts->end, elts->discard); @@ -2353,11 +2373,11 @@ static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file prim.prim = elts->prim; prim.offset = 0; /* offset from start of dma buffers */ prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - prim.vc_format = dev_priv->sarea_priv->vc_format; + prim.vc_format = sarea_priv->vc_format; - radeon_cp_dispatch_indices(dev, buf, &prim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &prim); if (elts->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2468,7 +2488,7 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil */ radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end); if (indirect->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2478,7 +2498,8 @@ static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; - 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; struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; drm_radeon_vertex2_t *vertex = data; @@ -2487,6 +2508,8 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file LOCK_TEST_WITH_RETURN(dev, file_priv); + sarea_priv = master_priv->sarea_priv; + DRM_DEBUG("pid=%d index=%d discard=%d\n", DRM_CURRENTPID, vertex->idx, vertex->discard); @@ -2547,12 +2570,12 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file tclprim.offset = prim.numverts * 64; tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - radeon_cp_dispatch_indices(dev, buf, &tclprim); + radeon_cp_dispatch_indices(dev, file_priv->master, buf, &tclprim); } else { tclprim.numverts = prim.numverts; tclprim.offset = 0; /* not used */ - radeon_cp_dispatch_vertex(dev, buf, &tclprim); + radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim); } if (sarea_priv->nbox == 1) @@ -2560,7 +2583,7 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file } if (vertex->discard) { - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); } COMMIT_RING(); @@ -2909,7 +2932,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file goto err; } - radeon_cp_discard_buffer(dev, buf); + radeon_cp_discard_buffer(dev, file_priv->master, buf); break; case RADEON_CMD_PACKET3: @@ -3020,7 +3043,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil */ case RADEON_PARAM_SAREA_HANDLE: /* The lock is the first dword in the sarea. */ - value = (long)dev->lock.hw_lock; +// value = (long)dev->lock.hw_lock; break; #endif case RADEON_PARAM_GART_TEX_HANDLE: @@ -3064,6 +3087,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_radeon_private_t *dev_priv = dev->dev_private; + struct drm_radeon_master_private *master_priv = file_priv->master->driver_priv; drm_radeon_setparam_t *sp = data; struct drm_radeon_driver_file_fields *radeon_priv; @@ -3078,12 +3102,14 @@ static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_fil DRM_DEBUG("color tiling disabled\n"); dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO; - dev_priv->sarea_priv->tiling_enabled = 0; + if (master_priv->sarea_priv) + master_priv->sarea_priv->tiling_enabled = 0; } else if (sp->value == 1) { DRM_DEBUG("color tiling enabled\n"); dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO; dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO; - dev_priv->sarea_priv->tiling_enabled = 1; + if (master_priv->sarea_priv) + master_priv->sarea_priv->tiling_enabled = 1; } break; case RADEON_SETPARAM_PCIGART_LOCATION: @@ -3129,14 +3155,6 @@ void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) void radeon_driver_lastclose(struct drm_device *dev) { - if (dev->dev_private) { - drm_radeon_private_t *dev_priv = dev->dev_private; - - if (dev_priv->sarea_priv && - dev_priv->sarea_priv->pfCurrentPage != 0) - radeon_cp_dispatch_flip(dev); - } - radeon_do_release(dev); } diff --git a/include/drm/drm.h b/include/drm/drm.h index ec5daa6..3a66252 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -635,6 +635,9 @@ struct drm_gem_open { #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_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_RM_CTX DRM_IOWR(0x21, struct drm_ctx) #define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 628505b..b7b8759 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -238,11 +238,11 @@ struct drm_device; */ #define LOCK_TEST_WITH_RETURN( dev, file_priv ) \ do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.file_priv != file_priv ) { \ + if ( !_DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ) || \ + file_priv->master->lock.file_priv != file_priv ) { \ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ - __func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ - dev->lock.file_priv, file_priv ); \ + __func__, _DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ),\ + file_priv->master->lock.file_priv, file_priv ); \ return -EINVAL; \ } \ } while (0) @@ -379,21 +379,25 @@ struct drm_buf_entry { /** File private data */ struct drm_file { int authenticated; - int master; pid_t pid; uid_t uid; drm_magic_t magic; unsigned long ioctl_count; struct list_head lhead; struct drm_minor *minor; - int remove_auth_on_close; unsigned long lock_count; + /** Mapping of mm object handles to object pointers. */ struct idr object_idr; /** Lock for synchronization of access to object_idr. */ spinlock_t table_lock; + struct file *filp; 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 */ @@ -523,6 +527,8 @@ struct drm_map_list { struct drm_hash_item hash; struct drm_map *map; /**< mapping */ uint64_t user_token; + struct drm_master *master; /** if this map is associated with a + specific master */ struct drm_mm_node *file_offset_node; /**< fake offset */ }; @@ -624,6 +630,30 @@ struct drm_gem_object { 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 * a family of cards. There will one drm_device for each card present @@ -724,6 +754,10 @@ struct drm_driver { void (*set_version) (struct drm_device *dev, 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); void (*proc_cleanup)(struct drm_minor *minor); @@ -767,6 +801,8 @@ struct drm_minor { struct device kdev; /**< Linux device */ struct drm_device *dev; struct proc_dir_entry *dev_root; /**< proc directory entry */ + struct drm_master *master; /* currently active master for this node */ + struct list_head master_list; }; /** @@ -774,13 +810,9 @@ struct drm_minor { * may contain multiple heads. */ struct drm_device { - char *unique; /**< Unique identifier: e.g., busid */ - int unique_len; /**< Length of unique field */ char *devname; /**< For /proc/interrupts */ int if_version; /**< Highest interface version set */ - int blocked; /**< Blocked due to VC switch? */ - /** \name Locks */ /*@{ */ spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ @@ -803,12 +835,6 @@ struct drm_device { atomic_t counts[15]; /*@} */ - /** \name Authentication */ - /*@{ */ - struct list_head filelist; - struct drm_open_hash magiclist; /**< magic hash table */ - struct list_head magicfree; - /*@} */ /** \name Memory management */ /*@{ */ @@ -825,7 +851,9 @@ struct drm_device { struct idr ctx_idr; struct list_head vmalist; /**< List of vmas (for debugging) */ - struct drm_lock_data lock; /**< Information on hardware lock */ + + struct list_head filelist; + /*@} */ /** \name DMA queues (contexts) */ @@ -1207,6 +1235,13 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); extern void drm_agp_chipset_flush(struct drm_device *dev); /* 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, struct drm_driver *driver); extern int drm_put_dev(struct drm_device *dev); -- 1.5.4.3