drm: cleanup buffer/map code
authorDave Airlie <airlied@starflyer.(none)>
Sun, 10 Jul 2005 09:27:04 +0000 (19:27 +1000)
committerDave Airlie <airlied@linux.ie>
Sun, 10 Jul 2005 09:27:04 +0000 (19:27 +1000)
This is a patch from DRM CVS that cleans up some code that was in CVS
that I never moved to the kernel, this patch produces the result of the
cleanups and puts it into the kernel drm.

From: Eric Anholt <anholt@freebsd.org>, Jon Smirl, Dave Airlie
Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/char/drm/drmP.h
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_fops.c
drivers/char/drm/drm_stub.c
drivers/char/drm/radeon_cp.c
drivers/char/drm/radeon_drv.c
drivers/char/drm/radeon_drv.h

index a7fdcec..fb2af92 100644 (file)
@@ -908,10 +908,11 @@ extern int drm_addbufs_agp(drm_device_t *dev, drm_buf_desc_t *request);
 extern int drm_addbufs_pci(drm_device_t *dev, drm_buf_desc_t *request);
 extern int drm_addmap(drm_device_t *dev, unsigned int offset,
                      unsigned int size, drm_map_type_t type,
-                     drm_map_flags_t flags, drm_map_t **map_ptr);
+                     drm_map_flags_t flags, drm_local_map_t **map_ptr);
 extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
                            unsigned int cmd, unsigned long arg);
-extern int drm_rmmap(drm_device_t *dev, void *handle);
+extern int drm_rmmap(drm_device_t *dev, drm_local_map_t *map);
+extern int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map);
 extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
                           unsigned int cmd, unsigned long arg);
 
@@ -926,6 +927,10 @@ extern int      drm_freebufs( struct inode *inode, struct file *filp,
                                    unsigned int cmd, unsigned long arg );
 extern int          drm_mapbufs( struct inode *inode, struct file *filp,
                                   unsigned int cmd, unsigned long arg );
+extern unsigned long drm_get_resource_start(drm_device_t *dev,
+                                           unsigned int resource);
+extern unsigned long drm_get_resource_len(drm_device_t *dev,
+                                         unsigned int resource);
 
                                /* DMA support (drm_dma.h) */
 extern int          drm_dma_setup(drm_device_t *dev);
index 06b0121..fcc8d24 100644 (file)
 #include <linux/vmalloc.h>
 #include "drmP.h"
 
-/**
- * Compute size order.  Returns the exponent of the smaller power of two which
- * is greater or equal to given number.
- * 
- * \param size size.
- * \return order.
- *
- * \todo Can be made faster.
- */
-int drm_order( unsigned long size )
+unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource)
 {
-       int order;
-       unsigned long tmp;
+       return pci_resource_start(dev->pdev, resource);
+}
+EXPORT_SYMBOL(drm_get_resource_start);
 
-       for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++)
-               ;
+unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource)
+{
+       return pci_resource_len(dev->pdev, resource);
+}
+EXPORT_SYMBOL(drm_get_resource_len);
 
-       if (size & (size - 1))
-               ++order;
+static drm_local_map_t *drm_find_matching_map(drm_device_t *dev,
+                                             drm_local_map_t *map)
+{
+       struct list_head *list;
 
-       return order;
+       list_for_each(list, &dev->maplist->head) {
+               drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
+               if (entry->map && map->type == entry->map->type &&
+                   entry->map->offset == map->offset) {
+                       return entry->map;
+               }
+       }
+
+       return NULL;
 }
-EXPORT_SYMBOL(drm_order);
 
 #ifdef CONFIG_COMPAT
 /*
@@ -89,6 +93,7 @@ int drm_addmap(drm_device_t * dev, unsigned int offset,
        drm_map_t *map;
        drm_map_list_t *list;
        drm_dma_handle_t *dmah;
+       drm_local_map_t *found_map;
 
        map = drm_alloc( sizeof(*map), DRM_MEM_MAPS );
        if ( !map )
@@ -129,6 +134,24 @@ int drm_addmap(drm_device_t * dev, unsigned int offset,
 #ifdef __alpha__
                map->offset += dev->hose->mem_space->start;
 #endif
+               /* Some drivers preinitialize some maps, without the X Server
+                * needing to be aware of it.  Therefore, we just return success
+                * when the server tries to create a duplicate map.
+                */
+               found_map = drm_find_matching_map(dev, map);
+               if (found_map != NULL) {
+                       if (found_map->size != map->size) {
+                               DRM_DEBUG("Matching maps of type %d with "
+                                  "mismatched sizes, (%ld vs %ld)\n",
+                                   map->type, map->size, found_map->size);
+                               found_map->size = map->size;
+                       }
+
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       *map_ptr = found_map;
+                       return 0;
+               }
+
                if (drm_core_has_MTRR(dev)) {
                        if ( map->type == _DRM_FRAME_BUFFER ||
                             (map->flags & _DRM_WRITE_COMBINING) ) {
@@ -270,93 +293,136 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
  *
  * \sa drm_addmap
  */
-int drm_rmmap(drm_device_t *dev, void *handle)
+int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
 {
        struct list_head *list;
        drm_map_list_t *r_list = NULL;
-       drm_vma_entry_t *pt, *prev;
-       drm_map_t *map;
-       int found_maps = 0;
+       drm_dma_handle_t dmah;
 
-       down(&dev->struct_sem);
-       list = &dev->maplist->head;
+       /* Find the list entry for the map and remove it */
        list_for_each(list, &dev->maplist->head) {
                r_list = list_entry(list, drm_map_list_t, head);
 
-               if(r_list->map &&
-                  r_list->map->handle == handle &&
-                  r_list->map->flags & _DRM_REMOVABLE) break;
+               if (r_list->map == map) {
+                       list_del(list);
+                       drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+                       break;
+               }
        }
 
-       /* List has wrapped around to the head pointer, or its empty we didn't
-        * find anything.
+       /* List has wrapped around to the head pointer, or it's empty and we
+        * didn't find anything.
         */
-       if(list == (&dev->maplist->head)) {
-               up(&dev->struct_sem);
+       if (list == (&dev->maplist->head)) {
                return -EINVAL;
        }
-       map = r_list->map;
-       list_del(list);
-       drm_free(list, sizeof(*list), DRM_MEM_MAPS);
-
-       for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
-               if (pt->vma->vm_private_data == map) found_maps++;
-       }
 
-       if(!found_maps) {
-               drm_dma_handle_t dmah;
-
-               switch (map->type) {
-               case _DRM_REGISTERS:
-               case _DRM_FRAME_BUFFER:
-                 if (drm_core_has_MTRR(dev)) {
-                               if (map->mtrr >= 0) {
-                                       int retcode;
-                                       retcode = mtrr_del(map->mtrr,
-                                                          map->offset,
-                                                          map->size);
-                                       DRM_DEBUG("mtrr_del = %d\n", retcode);
-                               }
-                       }
-                       drm_ioremapfree(map->handle, map->size, dev);
-                       break;
-               case _DRM_SHM:
-                       vfree(map->handle);
-                       break;
-               case _DRM_AGP:
-               case _DRM_SCATTER_GATHER:
-                       break;
-               case _DRM_CONSISTENT:
-                       dmah.vaddr = map->handle;
-                       dmah.busaddr = map->offset;
-                       dmah.size = map->size;
-                       __drm_pci_free(dev, &dmah);
-                       break;
+       switch (map->type) {
+       case _DRM_REGISTERS:
+               drm_ioremapfree(map->handle, map->size, dev);
+               /* FALLTHROUGH */
+       case _DRM_FRAME_BUFFER:
+               if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
+                       int retcode;
+                       retcode = mtrr_del(map->mtrr, map->offset,
+                                          map->size);
+                       DRM_DEBUG ("mtrr_del=%d\n", retcode);
                }
-               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+               break;
+       case _DRM_SHM:
+               vfree(map->handle);
+               break;
+       case _DRM_AGP:
+       case _DRM_SCATTER_GATHER:
+               break;
+       case _DRM_CONSISTENT:
+               dmah.vaddr = map->handle;
+               dmah.busaddr = map->offset;
+               dmah.size = map->size;
+               __drm_pci_free(dev, &dmah);
+               break;
        }
-       up(&dev->struct_sem);
+       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+
        return 0;
 }
+EXPORT_SYMBOL(drm_rmmap_locked);
+
+int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
+{
+       int ret;
+
+       down(&dev->struct_sem);
+       ret = drm_rmmap_locked(dev, map);
+       up(&dev->struct_sem);
+
+       return ret;
+}
 EXPORT_SYMBOL(drm_rmmap);
 
+/* The rmmap ioctl appears to be unnecessary.  All mappings are torn down on
+ * the last close of the device, and this is necessary for cleanup when things
+ * exit uncleanly.  Therefore, having userland manually remove mappings seems
+ * like a pointless exercise since they're going away anyway.
+ *
+ * One use case might be after addmap is allowed for normal users for SHM and
+ * gets used by drivers that the server doesn't need to care about.  This seems
+ * unlikely.
+ */
 int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
                    unsigned int cmd, unsigned long arg)
 {
        drm_file_t *priv = filp->private_data;
        drm_device_t *dev = priv->head->dev;
        drm_map_t request;
+       drm_local_map_t *map = NULL;
+       struct list_head *list;
+       int ret;
 
        if (copy_from_user(&request, (drm_map_t __user *)arg, sizeof(request))) {
                return -EFAULT;
        }
 
-       return drm_rmmap(dev, request.handle);
+       down(&dev->struct_sem);
+       list_for_each(list, &dev->maplist->head) {
+               drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
+
+               if (r_list->map &&
+                   r_list->map->handle == request.handle &&
+                   r_list->map->flags & _DRM_REMOVABLE) {
+                       map = r_list->map;
+                       break;
+               }
+       }
+
+       /* List has wrapped around to the head pointer, or its empty we didn't
+        * find anything.
+        */
+       if (list == (&dev->maplist->head)) {
+               up(&dev->struct_sem);
+               return -EINVAL;
+       }
+
+       if (!map)
+               return -EINVAL;
+
+       /* Register and framebuffer maps are permanent */
+       if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
+               up(&dev->struct_sem);
+               return 0;
+       }
+
+       ret = drm_rmmap_locked(dev, map);
+
+       up(&dev->struct_sem);
+
+       return ret;
 }
 
 /**
  * Cleanup after an error on one of the addbufs() functions.
  *
+ * \param dev DRM device.
  * \param entry buffer entry where the error occurred.
  *
  * Frees any pages and buffers associated with the given entry.
@@ -1470,3 +1536,26 @@ int drm_mapbufs( struct inode *inode, struct file *filp,
        return retcode;
 }
 
+/**
+ * Compute size order.  Returns the exponent of the smaller power of two which
+ * is greater or equal to given number.
+ * 
+ * \param size size.
+ * \return order.
+ *
+ * \todo Can be made faster.
+ */
+int drm_order( unsigned long size )
+{
+       int order;
+       unsigned long tmp;
+
+       for (order = 0, tmp = size >> 1; tmp; tmp >>= 1, order++)
+               ;
+
+       if (size & (size - 1))
+               ++order;
+
+       return order;
+}
+EXPORT_SYMBOL(drm_order);
index 733af58..6ba48f3 100644 (file)
@@ -132,9 +132,7 @@ static drm_ioctl_desc_t               drm_ioctls[] = {
 int drm_takedown( drm_device_t *dev )
 {
        drm_magic_entry_t *pt, *next;
-       drm_map_t *map;
        drm_map_list_t *r_list;
-       struct list_head *list, *list_next;
        drm_vma_entry_t *vma, *vma_next;
        int i;
 
@@ -142,6 +140,7 @@ int drm_takedown( drm_device_t *dev )
 
        if (dev->driver->pretakedown)
          dev->driver->pretakedown(dev);
+       DRM_DEBUG("driver pretakedown completed\n");
 
        if (dev->unique) {
                drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
@@ -184,6 +183,10 @@ int drm_takedown( drm_device_t *dev )
                dev->agp->acquired = 0;
                dev->agp->enabled  = 0;
        }
+       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
+               drm_sg_cleanup(dev->sg);
+               dev->sg = NULL;
+       }
 
                                /* Clear vma list (only built for debugging) */
        if ( dev->vmalist ) {
@@ -195,56 +198,11 @@ int drm_takedown( drm_device_t *dev )
        }
 
        if( dev->maplist ) {
-               list_for_each_safe( list, list_next, &dev->maplist->head ) {
-                       r_list = (drm_map_list_t *)list;
-
-                       if ( ( map = r_list->map ) ) {
-                               drm_dma_handle_t dmah;
-
-                               switch ( map->type ) {
-                               case _DRM_REGISTERS:
-                               case _DRM_FRAME_BUFFER:
-                                       if (drm_core_has_MTRR(dev)) {
-                                               if ( map->mtrr >= 0 ) {
-                                                       int retcode;
-                                                       retcode = mtrr_del( map->mtrr,
-                                                                           map->offset,
-                                                                           map->size );
-                                                       DRM_DEBUG( "mtrr_del=%d\n", retcode );
-                                               }
-                                       }
-                                       drm_ioremapfree( map->handle, map->size, dev );
-                                       break;
-                               case _DRM_SHM:
-                                       vfree(map->handle);
-                                       break;
-
-                               case _DRM_AGP:
-                                       /* Do nothing here, because this is all
-                                        * handled in the AGP/GART driver.
-                                        */
-                                       break;
-                               case _DRM_SCATTER_GATHER:
-                                       /* Handle it */
-                                       if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg) {
-                                               drm_sg_cleanup(dev->sg);
-                                               dev->sg = NULL;
-                                       }
-                                       break;
-                               case _DRM_CONSISTENT:
-                                       dmah.vaddr = map->handle;
-                                       dmah.busaddr = map->offset;
-                                       dmah.size = map->size;
-                                       __drm_pci_free(dev, &dmah);
-                                       break;
-                               }
-                               drm_free(map, sizeof(*map), DRM_MEM_MAPS);
-                       }
-                       list_del( list );
-                       drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS);
-               }
-               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
-               dev->maplist = NULL;
+               while (!list_empty(&dev->maplist->head)) {
+                       struct list_head *list = dev->maplist->head.next;
+                       r_list = list_entry(list, drm_map_list_t, head);
+                       drm_rmmap_locked(dev, r_list->map);
+               }
        }
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist ) {
@@ -273,6 +231,7 @@ int drm_takedown( drm_device_t *dev )
        }
        up( &dev->struct_sem );
 
+       DRM_DEBUG("takedown completed\n");
        return 0;
 }
 
@@ -334,6 +293,11 @@ static void drm_cleanup( drm_device_t *dev )
 
        drm_takedown( dev );    
 
+       if (dev->maplist) {
+               drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+               dev->maplist = NULL;
+       }
+
        drm_ctxbitmap_cleanup( dev );
        
        if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
index 10e64fd..a1f4e9c 100644 (file)
@@ -71,12 +71,6 @@ static int drm_setup( drm_device_t *dev )
                dev->magiclist[i].tail = NULL;
        }
 
-       dev->maplist = drm_alloc(sizeof(*dev->maplist),
-                                 DRM_MEM_MAPS);
-       if(dev->maplist == NULL) return -ENOMEM;
-       memset(dev->maplist, 0, sizeof(*dev->maplist));
-       INIT_LIST_HEAD(&dev->maplist->head);
-
        dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist),
                                  DRM_MEM_CTXLIST);
        if(dev->ctxlist == NULL) return -ENOMEM;
index 068ca9a..95a976c 100644 (file)
@@ -75,6 +75,11 @@ static int drm_fill_in_dev(drm_device_t *dev, struct pci_dev *pdev, const struct
        dev->pci_func = PCI_FUNC(pdev->devfn);
        dev->irq = pdev->irq;
 
+       dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
+       if (dev->maplist == NULL)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&dev->maplist->head);
+
        /* the DRM has 6 basic counters */
        dev->counters = 6;
        dev->types[0]  = _DRM_STAT_LOCK;
index 20bcf87..8255cc6 100644 (file)
@@ -2048,6 +2048,27 @@ int radeon_driver_preinit(struct drm_device *dev, unsigned long flags)
        return ret;
 }
 
+int radeon_presetup(struct drm_device *dev)
+{
+       int ret;
+       drm_local_map_t *map;
+       drm_radeon_private_t *dev_priv = dev->dev_private;
+
+       ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
+                        drm_get_resource_len(dev, 2), _DRM_REGISTERS,
+                        _DRM_READ_ONLY, &dev_priv->mmio);
+       if (ret != 0)
+               return ret;
+
+       ret = drm_addmap(dev, drm_get_resource_start(dev, 0),
+                        drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
+                        _DRM_WRITE_COMBINING, &map);
+       if (ret != 0)
+               return ret;
+
+       return 0;
+}
+
 int radeon_driver_postcleanup(struct drm_device *dev)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
index 18e4e5b..e0682f6 100644 (file)
@@ -76,6 +76,7 @@ static struct drm_driver driver = {
        .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
        .dev_priv_size = sizeof(drm_radeon_buf_priv_t),
        .preinit = radeon_driver_preinit,
+       .presetup = radeon_presetup,
        .postcleanup = radeon_driver_postcleanup,
        .prerelease = radeon_driver_prerelease,
        .pretakedown = radeon_driver_pretakedown,
index 771aa80..e701dff 100644 (file)
@@ -290,6 +290,7 @@ extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n );
 extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv );
 
 extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
+extern int radeon_presetup(struct drm_device *dev);
 extern int radeon_driver_postcleanup(struct drm_device *dev);
 
 extern int radeon_mem_alloc( DRM_IOCTL_ARGS );