* 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;
        }
  * 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);
                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;
  * 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);
 
                                ++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);
        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;
 
 {
        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;
                }
        }
                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: {
        list->user_token = list->hash.key << PAGE_SHIFT;
        mutex_unlock(&dev->struct_mutex);
 
+       list->master = dev->primary->master;
        *maplist = list;
        return 0;
        }
        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,
        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);
                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:
 
  * 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");
        }
 
        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;
 }
        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);
 
        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),
  */
 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;
 
                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);
 
        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;
                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]) {
        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);
-       }
        mutex_unlock(&dev->struct_mutex);
 
        DRM_DEBUG("lastclose completed\n");
 
 
 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);
                        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;
        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;
                        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);
 
 }
 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.
  *
                  (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);
        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);
 
        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;
 
                  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;
 }
                  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;
        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;
 }
        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];
                        /*
                         * Version 1.1 includes tying of DRM to specific device
                         */
-                       drm_set_busid(dev);
+                       drm_set_busid(dev, 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;
 
        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 */
                }
                        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");
        /* 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);
        }
 
 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",
        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. */
                }
        }
 
 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);
 
                         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;
 
                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));
 
        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,
                           const struct pci_device_id *ent,
                           struct drm_driver *driver)
 
        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);
        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);
 
 {
        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);
 
 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);
                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;
 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;
        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)
        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) {
        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.
         */
 
        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");
 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);
 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);
 
        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);
        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;
 }
 
                            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;
        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;
 
                          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;
        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;
 
        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;
 
        .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,
 
        int enabled;
 };
 
+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;
 
        int has_gem;
 
        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;
 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);
 
 {
        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;
        u32 iir, new_iir;
        u32 pipea_stats, pipeb_stats;
        u32 vblank_status;
                I915_WRITE(IIR, iir);
                new_iir = I915_READ(IIR); /* Flush posted writes */
 
-               if (dev_priv->sarea_priv)
-                       dev_priv->sarea_priv->last_dispatch =
-                               READ_BREADCRUMB(dev_priv);
+               if (dev->primary->master) {
+                       master_priv = dev->primary->master->driver_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);
 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);
        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(4);
        OUT_RING(MI_STORE_DWORD_INDEX);
 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,
                          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;
 }
 
 
 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;
 
  * 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;
 }
                      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;
                        }
 
                        emit_dispatch_age = 1;
-                       r300_discard_buffer(dev, buf);
+                       r300_discard_buffer(dev, file_priv->master, buf);
                        break;
 
                case R300_CMD_WAIT:
 
                /* 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();
        }
 
 
 
 #include "drmP.h"
 #include "drm.h"
+#include "drm_sarea.h"
 #include "radeon_drm.h"
 #include "radeon_drv.h"
 #include "r300_reg.h"
                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);
 
        }
 }
 
-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");
 
        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;
                }
        }
 
-       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);
        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);
        }
        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.
  */
 
 #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;
 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);
 
 } 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;                              \
 
  */
 
 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:
                 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);
        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.
        /* 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?
         */
        /* 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)
                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);
        }
  */
 
 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;
 
        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);
 
                /* 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;
                /* 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)) {
 
                /* 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++) {
 
 
                /* 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++) {
 
         * 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;
        /* 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.
                /* 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 {
         * 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
                     ((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();
         * 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();
 }
 } 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;
        } 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);
        }
 }
 
-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;
                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;
 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");
                               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;
 
 /* 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");
 
        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;
 }
        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;
 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);
        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;
 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;
 
        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);
 
                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();
 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;
 
        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);
        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();
         */
        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();
 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;
 
        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);
 
                        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)
        }
 
        if (vertex->discard) {
-               radeon_cp_discard_buffer(dev, buf);
+               radeon_cp_discard_buffer(dev, file_priv->master, buf);
        }
 
        COMMIT_RING();
                                goto err;
                        }
 
-                       radeon_cp_discard_buffer(dev, buf);
+                       radeon_cp_discard_buffer(dev, file_priv->master, buf);
                        break;
 
                case RADEON_CMD_PACKET3:
                 */
        case RADEON_PARAM_SAREA_HANDLE:
                /* The lock is the first dword in the sarea. */
-               value = (long)dev->lock.hw_lock;
+               /* no users of this parameter */
                break;
 #endif
        case RADEON_PARAM_GART_TEX_HANDLE:
 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;
 
                        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:
 
 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);
 }
 
 
 #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)
 
  */
 #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)
 /** 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 */
        struct drm_hash_item hash;
        struct drm_map *map;                    /**< mapping */
        uint64_t user_token;
+       struct drm_master *master;
 };
 
 typedef struct drm_map drm_local_map_t;
        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
        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);
 
        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;
 };
 
 /**
  */
 struct drm_device {
        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 */
        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 */
        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 */
        /*@{ */
        struct idr ctx_idr;
 
        struct list_head vmalist;       /**< List of vmas (for debugging) */
-       struct drm_lock_data lock;      /**< Information on hardware lock */
        /*@} */
 
        /** \name DMA queues (contexts) */
 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);
 
 
 /* SAREA area needs to be at least a page */
 #if defined(__alpha__)
-#define SAREA_MAX                       0x2000
+#define SAREA_MAX                       0x2000U
 #elif defined(__ia64__)
-#define SAREA_MAX                       0x10000        /* 64kB */
+#define SAREA_MAX                       0x10000U       /* 64kB */
 #else
 /* Intel 830M driver needs at least 8k SAREA */
-#define SAREA_MAX                       0x2000
+#define SAREA_MAX                       0x2000U
 #endif
 
 /** Maximum number of drawables in the SAREA */