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) {
+ ((entry->map->offset == map->offset) ||
+ (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
return entry;
}
}
if (!use_hashed_handle) {
int ret;
- hash->key = user_token;
+ hash->key = user_token >> PAGE_SHIFT;
ret = drm_ht_insert_item(&dev->map_hash, hash);
if (ret != -EINVAL)
return ret;
}
return drm_ht_just_insert_please(&dev->map_hash, hash,
user_token, 32 - PAGE_SHIFT - 3,
- PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
+ 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
}
/**
}
}
if (map->type == _DRM_REGISTERS)
- map->handle = drm_ioremap(map->offset, map->size, dev);
+ map->handle = ioremap(map->offset, map->size);
break;
-
case _DRM_SHM:
- map->handle = vmalloc_32(map->size);
+ list = drm_find_matching_map(dev, map);
+ if (list != NULL) {
+ if(list->map->size != map->size) {
+ DRM_DEBUG("Matching maps of type %d with "
+ "mismatched sizes, (%ld vs %ld)\n",
+ map->type, map->size, list->map->size);
+ list->map->size = map->size;
+ }
+
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ *maplist = list;
+ return 0;
+ }
+ map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
if (!map->handle) {
dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */
}
break;
- case _DRM_AGP:
- if (drm_core_has_AGP(dev)) {
+ case _DRM_AGP: {
+ drm_agp_mem_t *entry;
+ int valid = 0;
+
+ if (!drm_core_has_AGP(dev)) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
#ifdef __alpha__
- map->offset += dev->hose->mem_space->start;
+ map->offset += dev->hose->mem_space->start;
#endif
- map->offset += dev->agp->base;
- map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+ /* Note: dev->agp->base may actually be 0 when the DRM
+ * is not in control of AGP space. But if user space is
+ * it should already have added the AGP base itself.
+ */
+ map->offset += dev->agp->base;
+ map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+
+ /* This assumes the DRM is in total control of AGP space.
+ * It's not always the case as AGP can be in the control
+ * of user space (i.e. i810 driver). So this loop will get
+ * skipped and we double check that dev->agp->memory is
+ * actually set as well as being invalid before EPERM'ing
+ */
+ for (entry = dev->agp->memory; entry; entry = entry->next) {
+ if ((map->offset >= entry->bound) &&
+ (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) {
+ valid = 1;
+ break;
+ }
+ }
+ if (dev->agp->memory && !valid) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EPERM;
}
+ DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
+
break;
+ }
case _DRM_SCATTER_GATHER:
if (!dev->sg) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
if (!list) {
+ if (map->type == _DRM_REGISTERS)
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
map->offset;
ret = drm_map_handle(dev, &list->hash, user_token, 0);
if (ret) {
+ if (map->type == _DRM_REGISTERS)
+ iounmap(map->handle);
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
mutex_unlock(&dev->struct_mutex);
return ret;
}
- list->user_token = list->hash.key;
+ list->user_token = list->hash.key << PAGE_SHIFT;
mutex_unlock(&dev->struct_mutex);
*maplist = list;
return 0;
-}
+ }
int drm_addmap(drm_device_t * dev, unsigned int offset,
unsigned int size, drm_map_type_t type,
if (r_list->map == map) {
list_del(list);
- drm_ht_remove_key(&dev->map_hash, r_list->user_token);
+ drm_ht_remove_key(&dev->map_hash,
+ r_list->user_token >> PAGE_SHIFT);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
break;
}
switch (map->type) {
case _DRM_REGISTERS:
- drm_ioremapfree(map->handle, map->size, dev);
+ iounmap(map->handle);
/* FALLTHROUGH */
case _DRM_FRAME_BUFFER:
if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
{
drm_device_dma_t *dma = dev->dma;
drm_buf_entry_t *entry;
+ drm_agp_mem_t *agp_entry;
drm_buf_t *buf;
unsigned long offset;
unsigned long agp_offset;
int page_order;
int total;
int byte_count;
- int i;
+ int i, valid;
drm_buf_t **temp_buflist;
if (!dma)
if (dev->queue_count)
return -EBUSY; /* Not while in use */
+ /* Make sure buffers are located in AGP memory that we own */
+ valid = 0;
+ for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) {
+ if ((agp_offset >= agp_entry->bound) &&
+ (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
+ valid = 1;
+ break;
+ }
+ }
+ if (dev->agp->memory && !valid) {
+ DRM_DEBUG("zone invalid\n");
+ return -EINVAL;
+ }
spin_lock(&dev->count_lock);
if (dev->buf_use) {
spin_unlock(&dev->count_lock);
request->count = entry->buf_count;
request->size = size;
+ if (request->flags & _DRM_PCI_BUFFER_RO)
+ dma->flags = _DRM_DMA_USE_PCI_RO;
+
atomic_dec(&dev->buf_alloc);
return 0;
* \param arg pointer to a drm_buf_map structure.
* \return zero on success or a negative number on failure.
*
- * Maps the AGP or SG buffer region with do_mmap(), and copies information
- * about each buffer into user space. The PCI buffers are already mapped on the
- * addbufs_pci() call.
+ * Maps the AGP, SG or PCI buffer region with do_mmap(), and copies information
+ * about each buffer into user space. For PCI buffers, it calls do_mmap() with
+ * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
+ * drm_mmap_dma().
*/
int drm_mapbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)