diff options
Diffstat (limited to 'linux-core/drm_drv.c')
-rw-r--r-- | linux-core/drm_drv.c | 114 |
1 files changed, 103 insertions, 11 deletions
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 9712170b..518e2aa3 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -50,7 +50,7 @@ #include "drmP.h" #include "drm_core.h" -static void __exit drm_cleanup(drm_device_t * dev); +static void drm_cleanup(drm_device_t * dev); int drm_fb_loaded = 0; static int drm_version(struct inode *inode, struct file *filp, @@ -119,9 +119,16 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_FENCE)] = {drm_fence_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_BUFOBJ)] = {drm_bo_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_MM_INIT)] = {drm_mm_init_ioctl, + DRM_AUTH }, + + [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, }; -#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls ) +#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) + /** * Take down the DRM device. @@ -141,6 +148,11 @@ int drm_lastclose(drm_device_t * dev) DRM_DEBUG("\n"); + if (drm_bo_driver_finish(dev)) { + DRM_ERROR("DRM memory manager still busy. " + "System is unstable. Please reboot.\n"); + } + if (dev->driver->lastclose) dev->driver->lastclose(dev); DRM_DEBUG("driver lastclose completed\n"); @@ -154,6 +166,18 @@ int drm_lastclose(drm_device_t * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); + /* Free drawable information memory */ + for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield); + i++) { + drm_drawable_info_t *info = drm_get_drawable_info(dev, i); + + if (info) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + } + } + mutex_lock(&dev->struct_mutex); del_timer(&dev->timer); @@ -204,7 +228,7 @@ int drm_lastclose(drm_device_t * dev) if (dev->vmalist) { for (vma = dev->vmalist; vma; vma = vma_next) { vma_next = vma->next; - drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS); } dev->vmalist = NULL; } @@ -242,6 +266,7 @@ int drm_lastclose(drm_device_t * dev) dev->lock.filp = NULL; wake_up_interruptible(&dev->lock.lock_queue); } + dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); DRM_DEBUG("lastclose completed\n"); @@ -336,7 +361,7 @@ EXPORT_SYMBOL(drm_init); * * \sa drm_init */ -static void __exit drm_cleanup(drm_device_t * dev) +static void drm_cleanup(drm_device_t * dev) { DRM_DEBUG("\n"); @@ -346,11 +371,14 @@ static void __exit drm_cleanup(drm_device_t * dev) } drm_lastclose(dev); + drm_fence_manager_takedown(dev); if (dev->maplist) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; drm_ht_remove(&dev->map_hash); + drm_mm_takedown(&dev->offset_manager); + drm_ht_remove(&dev->object_hash); } if (!drm_fb_loaded) @@ -379,7 +407,7 @@ static void __exit drm_cleanup(drm_device_t * dev) DRM_ERROR("Cannot unload module\n"); } -void __exit drm_exit(struct drm_driver *driver) +void drm_exit(struct drm_driver *driver) { int i; drm_device_t *dev = NULL; @@ -405,6 +433,9 @@ void __exit drm_exit(struct drm_driver *driver) } } else pci_unregister_driver(&driver->pci_driver); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + free_nopage_retry(); +#endif DRM_INFO("Module unloaded\n"); } EXPORT_SYMBOL(drm_exit); @@ -415,10 +446,64 @@ static struct file_operations drm_stub_fops = { .open = drm_stub_open }; +static int drm_create_memory_caches(void) +{ + drm_cache.mm = kmem_cache_create("drm_mm_node_t", + sizeof(drm_mm_node_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL,NULL); + if (!drm_cache.mm) + return -ENOMEM; + + drm_cache.fence_object= kmem_cache_create("drm_fence_object_t", + sizeof(drm_fence_object_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL,NULL); + if (!drm_cache.fence_object) + return -ENOMEM; + + return 0; +} + +static void drm_free_mem_cache(kmem_cache_t *cache, + const char *name) +{ + if (!cache) + return; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + if (kmem_cache_destroy(cache)) { + DRM_ERROR("Warning! DRM is leaking %s memory.\n", + name); + } +#else + kmem_cache_destroy(cache); +#endif +} + +static void drm_free_memory_caches(void ) +{ + + drm_free_mem_cache(drm_cache.fence_object, "fence object"); + drm_cache.fence_object = NULL; + drm_free_mem_cache(drm_cache.mm, "memory manager block"); + drm_cache.mm = NULL; +} + + static int __init drm_core_init(void) { - int ret = -ENOMEM; + int ret; + struct sysinfo si; + + si_meminfo(&si); + drm_init_memctl(si.totalram/2, si.totalram*3/4); + ret = drm_create_memory_caches(); + if (ret) + goto err_p1; + 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); @@ -454,11 +539,13 @@ err_p2: unregister_chrdev(DRM_MAJOR, "drm"); drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); err_p1: + drm_free_memory_caches(); return ret; } static void __exit drm_core_exit(void) { + drm_free_memory_caches(); remove_proc_entry("dri", NULL); drm_sysfs_destroy(drm_class); @@ -535,14 +622,19 @@ int drm_ioctl(struct inode *inode, struct file *filp, current->pid, cmd, nr, (long)old_encode_dev(priv->head->device), priv->authenticated); - if (nr < DRIVER_IOCTL_COUNT) + if (nr >= DRIVER_IOCTL_COUNT && + (nr < DRM_COMMAND_BASE || nr >= DRM_COMMAND_END)) + goto err_i1; + if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) + && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; + else if (nr >= DRM_COMMAND_END || nr < DRM_COMMAND_BASE) ioctl = &drm_ioctls[nr]; - else if ((nr >= DRM_COMMAND_BASE) - && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) - ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; - else + else goto err_i1; + + func = ioctl->func; if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl) /* Local override? */ func = dev->driver->dma_ioctl; |