diff options
author | Thomas Hellstrom <thomas@tungstengraphics.com> | 2006-07-11 14:37:37 +0000 |
---|---|---|
committer | Thomas Hellstrom <thomas@tungstengraphics.com> | 2006-07-11 14:37:37 +0000 |
commit | 126673d62afad6da84e833daa644a352d88a5e37 (patch) | |
tree | 360d6186280ab586fe748bb9bccc7db298117841 /linux-core | |
parent | a392349691ec2aa3f83d8a9fc4a485e4dbef4bbe (diff) |
Keep hashed user tokens, with the following changes:
32-bit physical device addresses are mapped directly to user-tokens. No
duplicate maps are allowed, and the addresses are assumed to be outside
of the range 0x10000000 through 0x30000000. The user-token is identical
to the 32-bit physical start-address of the map.
64-bit physical device addressed are mapped to user-tokens in the range
0x10000000 to 0x30000000 with page-size increments. The user_token should
not be interpreted as an address.
Other map types, like upcoming TTM maps are mapped to user-tokens in the
range
0x10000000 to 0x30000000 with page-size increments. The user_token should
not be interpreted as an address.
This keeps compatibility with buggy drivers, while still implementing a
hashed map lookup. The SiS and via device driver major bumps are
reverted.
Diffstat (limited to 'linux-core')
-rw-r--r-- | linux-core/drm_bufs.c | 43 | ||||
-rw-r--r-- | linux-core/drm_hashtab.c | 14 | ||||
-rw-r--r-- | linux-core/drm_hashtab.h | 3 | ||||
-rw-r--r-- | linux-core/drm_sman.c | 2 | ||||
-rw-r--r-- | linux-core/drm_vm.c | 6 |
5 files changed, 47 insertions, 21 deletions
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 44705259..7dd46b69 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -65,6 +65,29 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, return NULL; } +int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, + unsigned long user_token, int hashed_handle) +{ + int use_hashed_handle; + +#if (BITS_PER_LONG == 64) + use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle); +#elif (BITS_PER_LONG == 32) + use_hashed_handle = hashed_handle; +#else +#error Unsupported long size. Neither 64 nor 32 bits. +#endif + + if (use_hashed_handle) { + return drm_ht_just_insert_please(&dev->map_hash, hash, + user_token, 32 - PAGE_SHIFT - 3, + PAGE_SHIFT, DRM_MAP_HASH_OFFSET); + } else { + hash->key = user_token; + return drm_ht_insert_item(&dev->map_hash, hash); + } +} + /** * Ioctl to specify a range of memory that is available for mapping by a non-root process. * @@ -85,6 +108,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, drm_map_t *map; drm_map_list_t *list; drm_dma_handle_t *dmah; + unsigned long user_token; + int ret; map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); if (!map) @@ -260,20 +285,21 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, down(&dev->struct_sem); list_add(&list->head, &dev->maplist->head); + /* Assign a 32-bit handle */ - /* We do it here so that dev->struct_sem protects the increment */ - if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, - ((map->type == _DRM_SHM) ? (unsigned long)map->handle : - map->offset) >> PAGE_SHIFT, - 32 - PAGE_SHIFT - 1)) { + user_token = (map->type == _DRM_SHM) ? (unsigned long) map->handle : + map->offset; + ret = drm_map_handle(dev, &list->hash, user_token, FALSE); + + if (ret) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); drm_free(list, sizeof(*list), DRM_MEM_MAPS); up(&dev->struct_sem); - return -ENOMEM; + return ret; } - list->user_token = (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; + list->user_token = list->hash.key; up(&dev->struct_sem); *maplist = list; @@ -358,8 +384,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) if (r_list->map == map) { list_del(list); - drm_ht_remove_key(&dev->map_hash, - (r_list->user_token - DRM_MAP_HASH_OFFSET) >> PAGE_SHIFT); + drm_ht_remove_key(&dev->map_hash, r_list->user_token); drm_free(list, sizeof(*list), DRM_MEM_MAPS); break; } diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c index 3be781df..d8c4549e 100644 --- a/linux-core/drm_hashtab.c +++ b/linux-core/drm_hashtab.c @@ -128,19 +128,21 @@ drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item) int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, - unsigned long seed, int bits) + unsigned long seed, int bits, int shift, + unsigned long add) { int ret; unsigned long mask = (1 << bits) - 1; - unsigned long first; + unsigned long first, unshifted_key; - item->key = hash_long(seed, bits); - first = item->key; + unshifted_key = hash_long(seed, bits); + first = unshifted_key; do{ + item->key = (unshifted_key << shift) + add; ret = drm_ht_insert_item(ht, item); if (ret) - item->key = (item->key + 1) & mask; - } while(ret && (item->key != first)); + unshifted_key = (unshifted_key + 1) & mask; + } while(ret && (unshifted_key != first)); if (ret) { DRM_ERROR("Available key bit space exhausted\n"); diff --git a/linux-core/drm_hashtab.h b/linux-core/drm_hashtab.h index d792499e..157353db 100644 --- a/linux-core/drm_hashtab.h +++ b/linux-core/drm_hashtab.h @@ -53,7 +53,8 @@ typedef struct drm_open_hash{ extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order); extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item); extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, - unsigned long seed, int bits); + unsigned long seed, int bits, int shift, + unsigned long add); extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item); extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key); diff --git a/linux-core/drm_sman.c b/linux-core/drm_sman.c index a03c9f55..d894e82c 100644 --- a/linux-core/drm_sman.c +++ b/linux-core/drm_sman.c @@ -223,7 +223,7 @@ drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman, unsigned int manager, if (drm_ht_just_insert_please (&sman->user_hash_tab, &memblock->user_hash, - (unsigned long)memblock, 32)) + (unsigned long)memblock, 32, 0, 0)) goto out1; owner_item = drm_sman_get_owner_item(sman, owner); diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 93037bda..19866dca 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -70,8 +70,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, if (!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; - if (drm_ht_find_item(&dev->map_hash, (VM_OFFSET(vma) - DRM_MAP_HASH_OFFSET) >> PAGE_SHIFT, - &hash)) + if (drm_ht_find_item(&dev->map_hash, VM_OFFSET(vma), &hash)) goto vm_nopage_error; r_list = drm_hash_entry(hash, drm_map_list_t, hash); @@ -575,8 +574,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) ) return drm_mmap_dma(filp, vma); - if (drm_ht_find_item(&dev->map_hash, (VM_OFFSET(vma) - DRM_MAP_HASH_OFFSET) >> PAGE_SHIFT, - &hash)) { + if (drm_ht_find_item(&dev->map_hash, VM_OFFSET(vma), &hash)) { DRM_ERROR("Could not find map\n"); return -EINVAL; } |