diff options
Diffstat (limited to 'linux-core/drm_stub.c')
-rw-r--r-- | linux-core/drm_stub.c | 242 |
1 files changed, 174 insertions, 68 deletions
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 00a24521..6856075b 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -37,38 +37,127 @@ #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; + + if (type == DRM_MINOR_CONTROL) { + base += 64; + limit = base + 127; + } else if (type == DRM_MINOR_RENDER) { + base += 128; + limit = base + 255; + } + +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; +} + +struct drm_master *drm_get_master(struct drm_minor *minor) +{ + struct drm_master *master; + + master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER); + if (!master) + return NULL; + +// INIT_LIST_HEAD(&master->filelist); + 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; +} + +void drm_put_master(struct drm_master *master) +{ + struct drm_magic_entry *pt, *next; + struct drm_device *dev = master->minor->dev; + + list_del(&master->head); + + if (dev->driver->master_destroy) + dev->driver->master_destroy(dev, master); + + if (master->unique) { + drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER); + master->unique = NULL; + master->unique_len = 0; + } + + list_for_each_entry_safe(pt, next, &master->magicfree, head) { + list_del(&pt->head); + drm_ht_remove_item(&master->magiclist, &pt->hash_item); + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + + drm_ht_remove(&master->magiclist); + + if (master->lock.hw_lock) { + if (dev->sigdata.lock == master->lock.hw_lock) + dev->sigdata.lock = NULL; + master->lock.hw_lock = NULL; /* SHM removed */ + master->lock.file_priv = NULL; + wake_up_interruptible(&master->lock.lock_queue); + } + + drm_free(master, sizeof(*master), DRM_MEM_DRIVER); +} + static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) { int retcode; - INIT_LIST_HEAD(&dev->filelist); INIT_LIST_HEAD(&dev->ctxlist); INIT_LIST_HEAD(&dev->vmalist); INIT_LIST_HEAD(&dev->maplist); + INIT_LIST_HEAD(&dev->filelist); spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); spin_lock_init(&dev->tasklet_lock); - spin_lock_init(&dev->lock.spinlock); +// spin_lock_init(&dev->lock.spinlock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); @@ -86,9 +175,9 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, dev->irq = pdev->irq; dev->irq_enabled = 0; - if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) { + if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) return -ENOMEM; - } + if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START, DRM_FILE_PAGE_OFFSET_SIZE)) { drm_ht_remove(&dev->map_hash); @@ -131,11 +220,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, } } - if (dev->driver->load) - if ((retcode = dev->driver->load(dev, ent->driver_data))) - goto error_out_unreg; - - retcode = drm_ctxbitmap_init(dev); if (retcode) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -161,49 +245,61 @@ 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; + INIT_LIST_HEAD(&new_minor->master_list); + + 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 +342,36 @@ 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))) - goto err_g3; + + /* only add the control node on a modesetting platform */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL))) + goto err_g3; + + if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) + goto err_g4; + + if (dev->driver->load) + if ((ret = dev->driver->load(dev, ent->driver_data))) + goto err_g5; 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_g5: + drm_put_minor(&dev->primary); +err_g4: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); +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); @@ -286,11 +396,6 @@ int drm_put_dev(struct drm_device * dev) { DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name); - if (dev->unique) { - drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER); - dev->unique = NULL; - dev->unique_len = 0; - } if (dev->devname) { drm_free(dev->devname, strlen(dev->devname) + 1, DRM_MEM_DRIVER); @@ -310,17 +415,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; } |