From 12574590cdf7871755d1939463ca6898251fd0d1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 6 Mar 2008 05:21:50 +1000 Subject: drm: reorganise minor number handling using code from modesetting branch Rip out the whole head thing and replace it with an idr and drm_minor structure. --- linux-core/drmP.h | 42 ++++++------ linux-core/drm_agpsupport.c | 2 +- linux-core/drm_bo.c | 14 ++-- linux-core/drm_bo_lock.c | 4 +- linux-core/drm_drv.c | 57 ++++++++--------- linux-core/drm_fence.c | 4 +- linux-core/drm_fops.c | 39 ++++++------ linux-core/drm_object.c | 16 ++--- linux-core/drm_proc.c | 67 ++++++++++++-------- linux-core/drm_stub.c | 151 ++++++++++++++++++++++++++++---------------- linux-core/drm_sysfs.c | 46 ++++++++------ linux-core/drm_vm.c | 20 +++--- linux-core/i810_dma.c | 4 +- 13 files changed, 261 insertions(+), 205 deletions(-) (limited to 'linux-core') diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f196e11d..1fea807b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -408,13 +408,12 @@ enum drm_ref_type { struct drm_file { int authenticated; int master; - int minor; pid_t pid; uid_t uid; drm_magic_t magic; unsigned long ioctl_count; struct list_head lhead; - struct drm_head *head; + struct drm_minor *minor; int remove_auth_on_close; unsigned long lock_count; @@ -721,16 +720,19 @@ struct drm_driver { struct pci_driver pci_driver; }; +#define DRM_MINOR_UNASSIGNED 0 +#define DRM_MINOR_LEGACY 1 + /** - * DRM head structure. This structure represent a video head on a card - * that may contain multiple heads. Embed one per head of these in the - * private drm_device structure. + * DRM minor structure. This structure represents a drm minor number. */ -struct drm_head { - int minor; /**< Minor device number */ +struct drm_minor { + int index; /**< Minor device number */ + int type; /**< Control or render */ + dev_t device; /**< Device number for mknod */ + struct device kdev; /**< Linux device */ struct drm_device *dev; struct proc_dir_entry *dev_root; /**< proc directory entry */ - dev_t device; /**< Device number for mknod */ struct class_device *dev_class; }; @@ -740,7 +742,6 @@ struct drm_head { * may contain multiple heads. */ struct drm_device { - struct device dev; /**< Linux device */ char *unique; /**< Unique identifier: e.g., busid */ int unique_len; /**< Length of unique field */ char *devname; /**< For /proc/interrupts */ @@ -870,7 +871,7 @@ struct drm_device { struct drm_driver *driver; drm_local_map_t *agp_buffer_map; unsigned int agp_buffer_token; - struct drm_head primary; /**< primary screen head */ + struct drm_minor *primary; /**< render type primary screen head */ struct drm_fence_manager fm; struct drm_buffer_manager bm; @@ -1187,23 +1188,20 @@ extern void drm_agp_chipset_flush(struct drm_device *dev); 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); -extern int drm_put_head(struct drm_head * head); +extern int drm_put_minor(struct drm_minor **minor); extern unsigned int drm_debug; /* 1 to enable debug output */ -extern unsigned int drm_cards_limit; -extern struct drm_head **drm_heads; + extern struct class *drm_class; extern struct proc_dir_entry *drm_proc_root; +extern struct idr drm_minors_idr; + extern drm_local_map_t *drm_getsarea(struct drm_device *dev); /* Proc support (drm_proc.h) */ -extern int drm_proc_init(struct drm_device *dev, - int minor, - struct proc_dir_entry *root, - struct proc_dir_entry **dev_root); -extern int drm_proc_cleanup(int minor, - struct proc_dir_entry *root, - struct proc_dir_entry *dev_root); +int drm_proc_init(struct drm_minor *minor, int minor_id, + struct proc_dir_entry *root); +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root); /* Scatter Gather Support (drm_scatter.h) */ extern void drm_sg_cleanup(struct drm_sg_mem * entry); @@ -1226,8 +1224,8 @@ extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t *dmah); struct drm_sysfs_class; extern struct class *drm_sysfs_create(struct module *owner, char *name); extern void drm_sysfs_destroy(void); -extern int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head); -extern void drm_sysfs_device_remove(struct drm_device *dev); +extern int drm_sysfs_device_add(struct drm_minor *minor); +extern void drm_sysfs_device_remove(struct drm_minor *minor); /* * Basic memory manager support (drm_mm.c) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index f58d5516..0aa94a75 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -130,7 +130,7 @@ EXPORT_SYMBOL(drm_agp_acquire); int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - return drm_agp_acquire((struct drm_device *) file_priv->head->dev); + return drm_agp_acquire((struct drm_device *) file_priv->minor->dev); } /** diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 17180d8d..95802fe2 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1190,7 +1190,7 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep) { struct drm_buffer_object *bo; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int ret = 0; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; @@ -1262,7 +1262,7 @@ out: static int drm_buffer_object_unmap(struct drm_file *file_priv, uint32_t handle) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; struct drm_ref_object *ro; int ret = 0; @@ -1654,7 +1654,7 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep, struct drm_buffer_object **bo_rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; int ret; @@ -1690,7 +1690,7 @@ EXPORT_SYMBOL(drm_bo_handle_validate); static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; mutex_lock(&dev->struct_mutex); @@ -1713,7 +1713,7 @@ static int drm_bo_handle_wait(struct drm_file *file_priv, uint32_t handle, uint32_t hint, struct drm_bo_info_rep *rep) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_buffer_object *bo; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; int ret; @@ -1833,7 +1833,7 @@ EXPORT_SYMBOL(drm_buffer_object_create); static int drm_bo_add_user_object(struct drm_file *file_priv, struct drm_buffer_object *bo, int shareable) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -1881,7 +1881,7 @@ int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *fil if (bo_type == drm_bo_type_user) req->flags &= ~DRM_BO_FLAG_SHAREABLE; - ret = drm_buffer_object_create(file_priv->head->dev, + ret = drm_buffer_object_create(file_priv->minor->dev, req->size, bo_type, req->flags, req->hint, req->page_alignment, req->buffer_start, &entry); diff --git a/linux-core/drm_bo_lock.c b/linux-core/drm_bo_lock.c index f967fb7c..2795384e 100644 --- a/linux-core/drm_bo_lock.c +++ b/linux-core/drm_bo_lock.c @@ -141,7 +141,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) * while holding it. */ - dev = file_priv->head->dev; + dev = file_priv->minor->dev; mutex_lock(&dev->struct_mutex); ret = drm_add_user_object(file_priv, &lock->base, 0); lock->base.remove = &drm_bo_write_lock_remove; @@ -156,7 +156,7 @@ int drm_bo_write_lock(struct drm_bo_lock *lock, struct drm_file *file_priv) int drm_bo_write_unlock(struct drm_bo_lock *lock, struct drm_file *file_priv) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_ref_object *ro; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 3c2794d0..1daa8653 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -416,35 +416,35 @@ static void drm_cleanup(struct drm_device * dev) drm_mm_takedown(&dev->offset_manager); drm_ht_remove(&dev->object_hash); - drm_put_head(&dev->primary); + drm_put_minor(&dev->primary); if (drm_put_dev(dev)) DRM_ERROR("Cannot unload module\n"); } -void drm_exit(struct drm_driver *driver) +int drm_minors_cleanup(int id, void *ptr, void *data) { - int i; - struct drm_device *dev = NULL; - struct drm_head *head; + struct drm_minor *minor = ptr; + struct drm_device *dev; + struct drm_driver *driver = data; + + dev = minor->dev; + if (minor->dev->driver != driver) + return 0; + + if (minor->type != DRM_MINOR_LEGACY) + return 0; + if (dev) + pci_dev_put(dev->pdev); + drm_cleanup(dev); + return 1; +} + +void drm_exit(struct drm_driver *driver) +{ DRM_DEBUG("\n"); if (drm_fb_loaded) { - for (i = 0; i < drm_cards_limit; i++) { - head = drm_heads[i]; - if (!head) - continue; - if (!head->dev) - continue; - if (head->dev->driver != driver) - continue; - dev = head->dev; - if (dev) { - /* release the pci driver */ - if (dev->pdev) - pci_dev_put(dev->pdev); - drm_cleanup(dev); - } - } + idr_for_each(&drm_minors_idr, &drm_minors_cleanup, driver); } else pci_unregister_driver(&driver->pci_driver); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) @@ -467,6 +467,7 @@ static int __init drm_core_init(void) unsigned long avail_memctl_mem; unsigned long max_memctl_mem; + idr_init(&drm_minors_idr); si_meminfo(&si); /* @@ -488,11 +489,6 @@ static int __init drm_core_init(void) drm_init_memctl(avail_memctl_mem/2, avail_memctl_mem*3/4, si.mem_unit); ret = -ENOMEM; - drm_cards_limit = - (drm_cards_limit < DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1); - drm_heads = drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB); - if (!drm_heads) - goto err_p1; if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) goto err_p1; @@ -521,7 +517,8 @@ err_p3: drm_sysfs_destroy(); err_p2: unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); + + idr_destroy(&drm_minors_idr); err_p1: return ret; } @@ -533,7 +530,7 @@ static void __exit drm_core_exit(void) unregister_chrdev(DRM_MAJOR, "drm"); - drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); + idr_destroy(&drm_minors_idr); } module_init(drm_core_init); @@ -593,7 +590,7 @@ EXPORT_SYMBOL(drm_ioctl); long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; struct drm_ioctl_desc *ioctl; drm_ioctl_t *func; unsigned int nr = DRM_IOCTL_NR(cmd); @@ -605,7 +602,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++file_priv->ioctl_count; DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", - current->pid, cmd, nr, (long)old_encode_dev(file_priv->head->device), + current->pid, cmd, nr, (long)old_encode_dev(file_priv->minor->device), file_priv->authenticated); if ((nr >= DRM_CORE_IOCTL_COUNT) && diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 247bc0a4..9d80327f 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -494,7 +494,7 @@ static int drm_fence_object_init(struct drm_device *dev, uint32_t fence_class, int drm_fence_add_user_object(struct drm_file *priv, struct drm_fence_object *fence, int shareable) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -590,7 +590,7 @@ void drm_fence_manager_takedown(struct drm_device *dev) struct drm_fence_object *drm_lookup_fence_object(struct drm_file *priv, uint32_t handle) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_fence_object *fence; diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 0e1c486c..7fe274a2 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -128,16 +128,15 @@ static int drm_setup(struct drm_device * dev) int drm_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; - int minor = iminor(inode); + int minor_id = iminor(inode); + struct drm_minor *minor; int retcode = 0; - if (!((minor >= 0) && (minor < drm_cards_limit))) + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) return -ENODEV; - if (!drm_heads[minor]) - return -ENODEV; - - if (!(dev = drm_heads[minor]->dev)) + if (!(dev = minor->dev)) return -ENODEV; retcode = drm_open_helper(inode, filp, dev); @@ -176,19 +175,18 @@ EXPORT_SYMBOL(drm_open); int drm_stub_open(struct inode *inode, struct file *filp) { struct drm_device *dev = NULL; - int minor = iminor(inode); + struct drm_minor *minor; + int minor_id = iminor(inode); int err = -ENODEV; const struct file_operations *old_fops; DRM_DEBUG("\n"); - if (!((minor >= 0) && (minor < drm_cards_limit))) + minor = idr_find(&drm_minors_idr, minor_id); + if (!minor) return -ENODEV; - - if (!drm_heads[minor]) - return -ENODEV; - - if (!(dev = drm_heads[minor]->dev)) + + if (!(dev = minor->dev)) return -ENODEV; old_fops = filp->f_op; @@ -233,7 +231,7 @@ static int drm_cpu_valid(void) static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev) { - int minor = iminor(inode); + int minor_id = iminor(inode); struct drm_file *priv; int ret; int i, j; @@ -243,7 +241,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, if (!drm_cpu_valid()) return -EINVAL; - DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); + DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor_id); priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); if (!priv) @@ -254,8 +252,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->filp = filp; priv->uid = current->euid; priv->pid = current->pid; - priv->minor = minor; - priv->head = drm_heads[minor]; + priv->minor = idr_find(&drm_minors_idr, minor_id); priv->ioctl_count = 0; /* for compatibility root is always authenticated */ priv->authenticated = capable(CAP_SYS_ADMIN); @@ -320,11 +317,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp, int drm_fasync(int fd, struct file *filp, int on) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int retcode; DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, - (long)old_encode_dev(priv->head->device)); + (long)old_encode_dev(priv->minor->device)); retcode = fasync_helper(fd, filp, on, &dev->buf_async); if (retcode < 0) return retcode; @@ -374,7 +371,7 @@ static void drm_object_release(struct file *filp) int drm_release(struct inode *inode, struct file *filp) { struct drm_file *file_priv = filp->private_data; - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; int retcode = 0; lock_kernel(); @@ -389,7 +386,7 @@ int drm_release(struct inode *inode, struct file *filp) */ DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", - current->pid, (long)old_encode_dev(file_priv->head->device), + current->pid, (long)old_encode_dev(file_priv->minor->device), dev->open_count); if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) { diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index 7d2e3a2b..2994b716 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -33,7 +33,7 @@ int drm_add_user_object(struct drm_file *priv, struct drm_user_object *item, int shareable) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; DRM_ASSERT_LOCKED(&dev->struct_mutex); @@ -58,7 +58,7 @@ EXPORT_SYMBOL(drm_add_user_object); struct drm_user_object *drm_lookup_user_object(struct drm_file *priv, uint32_t key) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_hash_item *hash; int ret; struct drm_user_object *item; @@ -85,7 +85,7 @@ EXPORT_SYMBOL(drm_lookup_user_object); static void drm_deref_user_object(struct drm_file *priv, struct drm_user_object *item) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; if (atomic_dec_and_test(&item->refcount)) { @@ -121,7 +121,7 @@ int drm_add_ref_object(struct drm_file *priv, struct drm_user_object *referenced struct drm_ref_object *item; struct drm_open_hash *ht = &priv->refd_object_hash[ref_action]; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); if (!referenced_object->shareable && priv != referenced_object->owner) { DRM_ERROR("Not allowed to reference this object\n"); return -EINVAL; @@ -178,7 +178,7 @@ struct drm_ref_object *drm_lookup_ref_object(struct drm_file *priv, struct drm_hash_item *hash; int ret; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); ret = drm_ht_find_item(&priv->refd_object_hash[ref_action], (unsigned long)referenced_object, &hash); if (ret) @@ -212,7 +212,7 @@ void drm_remove_ref_object(struct drm_file *priv, struct drm_ref_object *item) struct drm_open_hash *ht = &priv->refd_object_hash[item->unref_action]; enum drm_ref_type unref_action; - DRM_ASSERT_LOCKED(&priv->head->dev->struct_mutex); + DRM_ASSERT_LOCKED(&priv->minor->dev->struct_mutex); unref_action = item->unref_action; if (atomic_dec_and_test(&item->refcount)) { ret = drm_ht_remove_item(ht, &item->hash); @@ -239,7 +239,7 @@ EXPORT_SYMBOL(drm_remove_ref_object); int drm_user_object_ref(struct drm_file *priv, uint32_t user_token, enum drm_object_type type, struct drm_user_object **object) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_hash_item *hash; int ret; @@ -269,7 +269,7 @@ out_err: int drm_user_object_unref(struct drm_file *priv, uint32_t user_token, enum drm_object_type type) { - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_user_object *uo; struct drm_ref_object *ro; int ret; diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 3012c5b0..67afee8e 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -90,34 +90,35 @@ static struct drm_proc_list { * "/proc/dri/%minor%/", and each entry in proc_list as * "/proc/dri/%minor%/%name%". */ -int drm_proc_init(struct drm_device * dev, int minor, - struct proc_dir_entry *root, struct proc_dir_entry **dev_root) +int drm_proc_init(struct drm_minor *minor, int minor_id, + struct proc_dir_entry *root) { struct proc_dir_entry *ent; int i, j; char name[64]; - sprintf(name, "%d", minor); - *dev_root = proc_mkdir(name, root); - if (!*dev_root) { + sprintf(name, "%d", minor_id); + minor->dev_root = proc_mkdir(name, root); + if (!minor->dev_root) { DRM_ERROR("Cannot create /proc/dri/%s\n", name); return -1; } for (i = 0; i < DRM_PROC_ENTRIES; i++) { ent = create_proc_entry(drm_proc_list[i].name, - S_IFREG | S_IRUGO, *dev_root); + S_IFREG | S_IRUGO, minor->dev_root); if (!ent) { DRM_ERROR("Cannot create /proc/dri/%s/%s\n", name, drm_proc_list[i].name); for (j = 0; j < i; j++) remove_proc_entry(drm_proc_list[i].name, - *dev_root); + minor->dev_root); remove_proc_entry(name, root); + minor->dev_root = NULL; return -1; } ent->read_proc = drm_proc_list[i].f; - ent->data = dev; + ent->data = minor; } return 0; } @@ -132,18 +133,17 @@ int drm_proc_init(struct drm_device * dev, int minor, * * Remove all proc entries created by proc_init(). */ -int drm_proc_cleanup(int minor, struct proc_dir_entry *root, - struct proc_dir_entry *dev_root) +int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root) { int i; char name[64]; - if (!root || !dev_root) + if (!root || !minor->dev_root) return 0; for (i = 0; i < DRM_PROC_ENTRIES; i++) - remove_proc_entry(drm_proc_list[i].name, dev_root); - sprintf(name, "%d", minor); + remove_proc_entry(drm_proc_list[i].name, minor->dev_root); + sprintf(name, "%d", minor->index); remove_proc_entry(name, root); return 0; @@ -165,7 +165,8 @@ int drm_proc_cleanup(int minor, struct proc_dir_entry *root, static int drm_name_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; if (offset > DRM_PROC_LIMIT) { @@ -207,7 +208,8 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request, static int drm__vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_map *map; struct drm_map_list *r_list; @@ -264,7 +266,8 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, static int drm_vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -287,7 +290,8 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request, static int drm__queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; int i; struct drm_queue *q; @@ -337,7 +341,8 @@ static int drm__queues_info(char *buf, char **start, off_t offset, static int drm_queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -360,7 +365,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request, static int drm__bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_device_dma *dma = dev->dma; int i; @@ -409,7 +415,8 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request, static int drm_bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -432,7 +439,8 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, static int drm__objects_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_buffer_manager *bm = &dev->bm; struct drm_fence_manager *fm = &dev->fm; @@ -496,7 +504,8 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request, static int drm_objects_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -519,7 +528,8 @@ static int drm_objects_info(char *buf, char **start, off_t offset, int request, static int drm__clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_file *priv; @@ -535,7 +545,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset, list_for_each_entry(priv, &dev->filelist, lhead) { DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", priv->authenticated ? 'y' : 'n', - priv->minor, + priv->minor->index, priv->pid, priv->uid, priv->magic, priv->ioctl_count); } @@ -552,7 +562,8 @@ static int drm__clients_info(char *buf, char **start, off_t offset, static int drm_clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); @@ -566,7 +577,8 @@ static int drm_clients_info(char *buf, char **start, off_t offset, static int drm__vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int len = 0; struct drm_vma_entry *pt; struct vm_area_struct *vma; @@ -625,7 +637,8 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, static int drm_vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) { - struct drm_device *dev = (struct drm_device *) data; + struct drm_minor *minor = (struct drm_minor *) data; + struct drm_device *dev = minor->dev; int ret; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 00a24521..6584f51d 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -37,23 +37,49 @@ #include "drmP.h" #include "drm_core.h" -unsigned int drm_cards_limit = 16; /* Enough for one machine */ unsigned int drm_debug = 0; /* 1 to enable debug output */ EXPORT_SYMBOL(drm_debug); MODULE_AUTHOR(CORE_AUTHOR); MODULE_DESCRIPTION(CORE_DESC); MODULE_LICENSE("GPL and additional rights"); -MODULE_PARM_DESC(cards_limit, "Maximum number of graphics cards"); MODULE_PARM_DESC(debug, "Enable debug output"); -module_param_named(cards_limit, drm_cards_limit, int, 0444); module_param_named(debug, drm_debug, int, 0600); -struct drm_head **drm_heads; +struct idr drm_minors_idr; + struct class *drm_class; struct proc_dir_entry *drm_proc_root; +static int drm_minor_get_id(struct drm_device *dev, int type) +{ + int new_id; + int ret; + int base = 0, limit = 63; + +again: + if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) { + DRM_ERROR("Out of memory expanding drawable idr\n"); + return -ENOMEM; + } + mutex_lock(&dev->struct_mutex); + ret = idr_get_new_above(&drm_minors_idr, NULL, + base, &new_id); + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) { + goto again; + } else if (ret) { + return ret; + } + + if (new_id >= limit) { + idr_remove(&drm_minors_idr, new_id); + return -EINVAL; + } + return new_id; +} + static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) @@ -161,49 +187,60 @@ error_out_unreg: * create the proc init entry via proc_init(). This routines assigns * minor numbers to secondary heads of multi-headed cards */ -static int drm_get_head(struct drm_device * dev, struct drm_head * head) +static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) { - struct drm_head **heads = drm_heads; + struct drm_minor *new_minor; int ret; - int minor; + int minor_id; DRM_DEBUG("\n"); - for (minor = 0; minor < drm_cards_limit; minor++, heads++) { - if (!*heads) { - - *head = (struct drm_head) { - .dev = dev, - .device = MKDEV(DRM_MAJOR, minor), - .minor = minor, - }; - if ((ret = - drm_proc_init(dev, minor, drm_proc_root, - &head->dev_root))) { - printk(KERN_ERR - "DRM: Failed to initialize /proc/dri.\n"); - goto err_g1; - } - - ret = drm_sysfs_device_add(dev, head); - if (ret) { - printk(KERN_ERR - "DRM: Error sysfs_device_add.\n"); - goto err_g2; - } - *heads = head; - - DRM_DEBUG("new minor assigned %d\n", minor); - return 0; + minor_id = drm_minor_get_id(dev, type); + if (minor_id < 0) + return minor_id; + + new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL); + if (!new_minor) { + ret = -ENOMEM; + goto err_idr; + } + + new_minor->type = type; + new_minor->device = MKDEV(DRM_MAJOR, minor_id); + new_minor->dev = dev; + new_minor->index = minor_id; + + idr_replace(&drm_minors_idr, new_minor, minor_id); + + if (type == DRM_MINOR_LEGACY) { + ret = drm_proc_init(new_minor, minor_id, drm_proc_root); + if (ret) { + DRM_ERROR("DRM: Failed to initialize /proc/dri.\n"); + goto err_mem; } + } else + new_minor->dev_root = NULL; + + ret = drm_sysfs_device_add(new_minor); + if (ret) { + printk(KERN_ERR + "DRM: Error sysfs_device_add.\n"); + goto err_g2; } - DRM_ERROR("out of minors\n"); - return -ENOMEM; + *minor = new_minor; + + DRM_DEBUG("new minor assigned %d\n", minor_id); + return 0; + + err_g2: - drm_proc_cleanup(minor, drm_proc_root, head->dev_root); -err_g1: - *head = (struct drm_head) { - .dev = NULL}; + if (new_minor->type == DRM_MINOR_LEGACY) + drm_proc_cleanup(new_minor, drm_proc_root); +err_mem: + kfree(new_minor); +err_idr: + idr_remove(&drm_minors_idr, minor_id); + *minor = NULL; return ret; } @@ -246,22 +283,29 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, printk(KERN_ERR "DRM: fill_in_dev failed\n"); goto err_g3; } - if ((ret = drm_get_head(dev, &dev->primary))) + + /* only add the control node on a modesetting platform */ + if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) goto err_g3; + if (dev->driver->load) + if ((ret = dev->driver->load(dev, ent->driver_data))) + goto err_g4; + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, - driver->date, dev->primary.minor); + driver->date, dev->primary->index); return 0; - - err_g3: +err_g4: + drm_put_minor(&dev->primary); +err_g3: if (!drm_fb_loaded) pci_disable_device(pdev); - err_g2: +err_g2: if (!drm_fb_loaded) pci_release_regions(pdev); - err_g1: +err_g1: if (!drm_fb_loaded) pci_set_drvdata(pdev, NULL); @@ -310,17 +354,18 @@ int drm_put_dev(struct drm_device * dev) * last minor released. * */ -int drm_put_head(struct drm_head * head) +int drm_put_minor(struct drm_minor **minor_p) { - int minor = head->minor; - - DRM_DEBUG("release secondary minor %d\n", minor); + struct drm_minor *minor = *minor_p; + DRM_DEBUG("release secondary minor %d\n", minor->index); - drm_proc_cleanup(minor, drm_proc_root, head->dev_root); - drm_sysfs_device_remove(head->dev); + if (minor->type == DRM_MINOR_LEGACY) + drm_proc_cleanup(minor, drm_proc_root); + drm_sysfs_device_remove(minor); - *head = (struct drm_head) {.dev = NULL}; + idr_remove(&drm_minors_idr, minor->index); - drm_heads[minor] = NULL; + kfree(minor); + *minor_p = NULL; return 0; } diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index c02e2049..32759424 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -19,7 +19,7 @@ #include "drm_core.h" #include "drmP.h" -#define to_drm_device(d) container_of(d, struct drm_device, dev) +#define to_drm_minor(d) container_of(d, struct drm_minor, kdev) /** * drm_sysfs_suspend - DRM class suspend hook @@ -31,7 +31,8 @@ */ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; printk(KERN_ERR "%s\n", __FUNCTION__); @@ -50,7 +51,8 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) */ static int drm_sysfs_resume(struct device *dev) { - struct drm_device *drm_dev = to_drm_device(dev); + struct drm_minor *drm_minor = to_drm_minor(dev); + struct drm_device *drm_dev = drm_minor->dev; if (drm_dev->driver->resume) return drm_dev->driver->resume(drm_dev); @@ -122,10 +124,11 @@ void drm_sysfs_destroy(void) static ssize_t show_dri(struct device *device, struct device_attribute *attr, char *buf) { - struct drm_device *dev = to_drm_device(device); - if (dev->driver->dri_library_name) - return dev->driver->dri_library_name(dev, buf); - return snprintf(buf, PAGE_SIZE, "%s\n", dev->driver->pci_driver.name); + struct drm_minor *drm_minor = to_drm_minor(device); + struct drm_device *drm_dev = drm_minor->dev; + if (drm_dev->driver->dri_library_name) + return drm_dev->driver->dri_library_name(drm_dev, buf); + return snprintf(buf, PAGE_SIZE, "%s\n", drm_dev->driver->pci_driver.name); } static struct device_attribute device_attrs[] = { @@ -154,25 +157,28 @@ static void drm_sysfs_device_release(struct device *dev) * as the parent for the Linux device, and make sure it has a file containing * the driver we're using (for userspace compatibility). */ -int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) +int drm_sysfs_device_add(struct drm_minor *minor) { int err; int i, j; + char *minor_str; - dev->dev.parent = &dev->pdev->dev; - dev->dev.class = drm_class; - dev->dev.release = drm_sysfs_device_release; - dev->dev.devt = head->device; - snprintf(dev->dev.bus_id, BUS_ID_SIZE, "card%d", head->minor); + minor->kdev.parent = &minor->dev->pdev->dev; + minor->kdev.class = drm_class; + minor->kdev.release = drm_sysfs_device_release; + minor->kdev.devt = minor->device; + minor_str = "card%d"; + + snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index); - err = device_register(&dev->dev); + err = device_register(&minor->kdev); if (err) { DRM_ERROR("device add failed: %d\n", err); goto err_out; } for (i = 0; i < ARRAY_SIZE(device_attrs); i++) { - err = device_create_file(&dev->dev, &device_attrs[i]); + err = device_create_file(&minor->kdev, &device_attrs[i]); if (err) goto err_out_files; } @@ -182,8 +188,8 @@ int drm_sysfs_device_add(struct drm_device *dev, struct drm_head *head) err_out_files: if (i > 0) for (j = 0; j < i; j++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); err_out: return err; @@ -196,11 +202,11 @@ err_out: * This call unregisters and cleans up a class device that was created with a * call to drm_sysfs_device_add() */ -void drm_sysfs_device_remove(struct drm_device *dev) +void drm_sysfs_device_remove(struct drm_minor *minor) { int i; for (i = 0; i < ARRAY_SIZE(device_attrs); i++) - device_remove_file(&dev->dev, &device_attrs[i]); - device_unregister(&dev->dev); + device_remove_file(&minor->kdev, &device_attrs[i]); + device_unregister(&minor->kdev); } diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index c481a530..15e1c0f5 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -86,7 +86,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, unsigned long address) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_map *map = NULL; struct drm_map_list *r_list; struct drm_hash_item *hash; @@ -204,7 +204,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, static void drm_vm_shm_close(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *pt, *temp; struct drm_map *map; struct drm_map_list *r_list; @@ -286,7 +286,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma, unsigned long address) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_device_dma *dma = dev->dma; unsigned long offset; unsigned long page_nr; @@ -323,7 +323,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma, { struct drm_map *map = (struct drm_map *) vma->vm_private_data; struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_sg_mem *entry = dev->sg; unsigned long offset; unsigned long map_offset; @@ -419,7 +419,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { static void drm_vm_open_locked(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *vma_entry; DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -437,7 +437,7 @@ static void drm_vm_open_locked(struct vm_area_struct *vma) static void drm_vm_open(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; mutex_lock(&dev->struct_mutex); drm_vm_open_locked(vma); @@ -455,7 +455,7 @@ static void drm_vm_open(struct vm_area_struct *vma) static void drm_vm_close(struct vm_area_struct *vma) { struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_vma_entry *pt, *temp; DRM_DEBUG("0x%08lx,0x%08lx\n", @@ -491,7 +491,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) struct drm_device_dma *dma; unsigned long length = vma->vm_end - vma->vm_start; - dev = priv->head->dev; + dev = priv->minor->dev; dma = dev->dma; DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", vma->vm_start, vma->vm_end, vma->vm_pgoff); @@ -556,7 +556,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs); static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; struct drm_map *map = NULL; unsigned long offset = 0; struct drm_hash_item *hash; @@ -677,7 +677,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) int drm_mmap(struct file *filp, struct vm_area_struct *vma) { struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->head->dev; + struct drm_device *dev = priv->minor->dev; int ret; mutex_lock(&dev->struct_mutex); diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 3c9ca3b2..f2bf5d9d 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -113,7 +113,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) drm_i810_buf_priv_t *buf_priv; lock_kernel(); - dev = priv->head->dev; + dev = priv->minor->dev; dev_priv = dev->dev_private; buf = dev_priv->mmap_buffer; buf_priv = buf->dev_private; @@ -141,7 +141,7 @@ static const struct file_operations i810_buffer_fops = { static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) { - struct drm_device *dev = file_priv->head->dev; + struct drm_device *dev = file_priv->minor->dev; drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_private_t *dev_priv = dev->dev_private; const struct file_operations *old_fops; -- cgit v1.2.3