aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/drm')
-rw-r--r--drivers/char/drm/drmP.h9
-rw-r--r--drivers/char/drm/drm_bufs.c229
-rw-r--r--drivers/char/drm/drm_drv.c68
-rw-r--r--drivers/char/drm/drm_fops.c6
-rw-r--r--drivers/char/drm/drm_stub.c5
-rw-r--r--drivers/char/drm/radeon_cp.c21
-rw-r--r--drivers/char/drm/radeon_drv.c1
-rw-r--r--drivers/char/drm/radeon_drv.h1
8 files changed, 210 insertions, 130 deletions
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index a7fdcece612..fb2af927914 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -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);
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 06b01215fdf..fcc8d244f46 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -36,29 +36,33 @@
#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);
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 733af58fb3a..6ba48f346fc 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -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) &&
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 10e64fde8d7..a1f4e9cd64e 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -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;
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 068ca9a8b0b..95a976c96eb 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -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;
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 20bcf872b34..8255cc6fdc2 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -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;
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index 18e4e5b0952..e0682f64b40 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -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,
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 771aa80a5e8..e701dffe978 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -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 );