aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas@tungstengraphics.com>2006-08-07 08:36:47 -0400
committerDave Airlie <airlied@linux.ie>2006-09-21 15:32:31 -0400
commit8d153f7107ff2c5d6e32053ae377c961187ab6b9 (patch)
treec90cdf1bf8e04237e840b37033fc0f57b74ab292
parent8669cbc5e651bf4effa20e8c244a5a7d67da6fe9 (diff)
drm: update user token hashing and map handles
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. Implement hashed map lookups. Signed-off-by: Dave Airlie <airlied@linux.ie>
-rw-r--r--drivers/char/drm/drmP.h3
-rw-r--r--drivers/char/drm/drm_bufs.c68
-rw-r--r--drivers/char/drm/drm_hashtab.h2
-rw-r--r--drivers/char/drm/drm_stub.c4
-rw-r--r--drivers/char/drm/drm_vm.c37
5 files changed, 51 insertions, 63 deletions
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index fedaf013f848..84e9c18fdbef 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -140,6 +140,7 @@
140#define DRM_MEM_HASHTAB 23 140#define DRM_MEM_HASHTAB 23
141 141
142#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) 142#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
143#define DRM_MAP_HASH_OFFSET 0x10000000
143 144
144/*@}*/ 145/*@}*/
145 146
@@ -485,6 +486,7 @@ typedef struct drm_sigdata {
485 */ 486 */
486typedef struct drm_map_list { 487typedef struct drm_map_list {
487 struct list_head head; /**< list head */ 488 struct list_head head; /**< list head */
489 drm_hash_item_t hash;
488 drm_map_t *map; /**< mapping */ 490 drm_map_t *map; /**< mapping */
489 unsigned int user_token; 491 unsigned int user_token;
490} drm_map_list_t; 492} drm_map_list_t;
@@ -662,6 +664,7 @@ typedef struct drm_device {
662 /*@{ */ 664 /*@{ */
663 drm_map_list_t *maplist; /**< Linked list of regions */ 665 drm_map_list_t *maplist; /**< Linked list of regions */
664 int map_count; /**< Number of mappable regions */ 666 int map_count; /**< Number of mappable regions */
667 drm_open_hash_t map_hash; /**< User token hash table for maps */
665 668
666 /** \name Context handle management */ 669 /** \name Context handle management */
667 /*@{ */ 670 /*@{ */
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 7775fb5dfb9b..4440257f33e4 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -65,43 +65,27 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
65 return NULL; 65 return NULL;
66} 66}
67 67
68/* 68int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
69 * Used to allocate 32-bit handles for mappings. 69 unsigned long user_token, int hashed_handle)
70 */
71#define START_RANGE 0x10000000
72#define END_RANGE 0x40000000
73
74#ifdef _LP64
75static __inline__ unsigned int HandleID(unsigned long lhandle,
76 drm_device_t *dev)
77{ 70{
78 static unsigned int map32_handle = START_RANGE; 71 int use_hashed_handle;
79 unsigned int hash; 72 #if (BITS_PER_LONG == 64)
80 73 use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
81 if (lhandle & 0xffffffff00000000) { 74#elif (BITS_PER_LONG == 32)
82 hash = map32_handle; 75 use_hashed_handle = hashed_handle;
83 map32_handle += PAGE_SIZE; 76#else
84 if (map32_handle > END_RANGE) 77#error Unsupported long size. Neither 64 nor 32 bits.
85 map32_handle = START_RANGE; 78#endif
86 } else
87 hash = lhandle;
88
89 while (1) {
90 drm_map_list_t *_entry;
91 list_for_each_entry(_entry, &dev->maplist->head, head) {
92 if (_entry->user_token == hash)
93 break;
94 }
95 if (&_entry->head == &dev->maplist->head)
96 return hash;
97 79
98 hash += PAGE_SIZE; 80 if (use_hashed_handle) {
99 map32_handle += PAGE_SIZE; 81 return drm_ht_just_insert_please(&dev->map_hash, hash,
82 user_token, 32 - PAGE_SHIFT - 3,
83 PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
84 } else {
85 hash->key = user_token;
86 return drm_ht_insert_item(&dev->map_hash, hash);
100 } 87 }
101} 88}
102#else
103# define HandleID(x,dev) (unsigned int)(x)
104#endif
105 89
106/** 90/**
107 * Ioctl to specify a range of memory that is available for mapping by a non-root process. 91 * Ioctl to specify a range of memory that is available for mapping by a non-root process.
@@ -123,6 +107,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
123 drm_map_t *map; 107 drm_map_t *map;
124 drm_map_list_t *list; 108 drm_map_list_t *list;
125 drm_dma_handle_t *dmah; 109 drm_dma_handle_t *dmah;
110 unsigned long user_token;
111 int ret;
126 112
127 map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); 113 map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
128 if (!map) 114 if (!map)
@@ -257,11 +243,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
257 243
258 mutex_lock(&dev->struct_mutex); 244 mutex_lock(&dev->struct_mutex);
259 list_add(&list->head, &dev->maplist->head); 245 list_add(&list->head, &dev->maplist->head);
246
260 /* Assign a 32-bit handle */ 247 /* Assign a 32-bit handle */
261 /* We do it here so that dev->struct_mutex protects the increment */ 248 /* We do it here so that dev->struct_mutex protects the increment */
262 list->user_token = HandleID(map->type == _DRM_SHM 249 user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
263 ? (unsigned long)map->handle 250 map->offset;
264 : map->offset, dev); 251 ret = drm_map_handle(dev, &list->hash, user_token, FALSE);
252 if (ret) {
253 drm_free(map, sizeof(*map), DRM_MEM_MAPS);
254 drm_free(list, sizeof(*list), DRM_MEM_MAPS);
255 mutex_unlock(&dev->struct_mutex);
256 return ret;
257 }
258
259 list->user_token = list->hash.key;
265 mutex_unlock(&dev->struct_mutex); 260 mutex_unlock(&dev->struct_mutex);
266 261
267 *maplist = list; 262 *maplist = list;
@@ -346,6 +341,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
346 341
347 if (r_list->map == map) { 342 if (r_list->map == map) {
348 list_del(list); 343 list_del(list);
344 drm_ht_remove_key(&dev->map_hash, r_list->user_token);
349 drm_free(list, sizeof(*list), DRM_MEM_MAPS); 345 drm_free(list, sizeof(*list), DRM_MEM_MAPS);
350 break; 346 break;
351 } 347 }
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
index 9e19ef1814ba..40afec05bff8 100644
--- a/drivers/char/drm/drm_hashtab.h
+++ b/drivers/char/drm/drm_hashtab.h
@@ -35,7 +35,7 @@
35#ifndef DRM_HASHTAB_H 35#ifndef DRM_HASHTAB_H
36#define DRM_HASHTAB_H 36#define DRM_HASHTAB_H
37 37
38#define drm_hash_entry(_ptr, _type, _member) list_entry(_ptr, _type, _member) 38#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
39 39
40typedef struct drm_hash_item{ 40typedef struct drm_hash_item{
41 struct hlist_node head; 41 struct hlist_node head;
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index b1ead37c51d6..a9bb18ac3a2b 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -75,6 +75,10 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
75 if (dev->maplist == NULL) 75 if (dev->maplist == NULL)
76 return -ENOMEM; 76 return -ENOMEM;
77 INIT_LIST_HEAD(&dev->maplist->head); 77 INIT_LIST_HEAD(&dev->maplist->head);
78 if (drm_ht_create(&dev->map_hash, 12)) {
79 drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
80 return -ENOMEM;
81 }
78 82
79 /* the DRM has 6 basic counters */ 83 /* the DRM has 6 basic counters */
80 dev->counters = 6; 84 dev->counters = 6;
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index afb4f0a44b81..b40ae438f531 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
59 drm_device_t *dev = priv->head->dev; 59 drm_device_t *dev = priv->head->dev;
60 drm_map_t *map = NULL; 60 drm_map_t *map = NULL;
61 drm_map_list_t *r_list; 61 drm_map_list_t *r_list;
62 struct list_head *list; 62 drm_hash_item_t *hash;
63 63
64 /* 64 /*
65 * Find the right map 65 * Find the right map
@@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
70 if (!dev->agp || !dev->agp->cant_use_aperture) 70 if (!dev->agp || !dev->agp->cant_use_aperture)
71 goto vm_nopage_error; 71 goto vm_nopage_error;
72 72
73 list_for_each(list, &dev->maplist->head) { 73 if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
74 r_list = list_entry(list, drm_map_list_t, head); 74 goto vm_nopage_error;
75 map = r_list->map; 75
76 if (!map) 76 r_list = drm_hash_entry(hash, drm_map_list_t, hash);
77 continue; 77 map = r_list->map;
78 if (r_list->user_token == (vma->vm_pgoff << PAGE_SHIFT))
79 break;
80 }
81 78
82 if (map && map->type == _DRM_AGP) { 79 if (map && map->type == _DRM_AGP) {
83 unsigned long offset = address - vma->vm_start; 80 unsigned long offset = address - vma->vm_start;
@@ -521,9 +518,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
521 drm_file_t *priv = filp->private_data; 518 drm_file_t *priv = filp->private_data;
522 drm_device_t *dev = priv->head->dev; 519 drm_device_t *dev = priv->head->dev;
523 drm_map_t *map = NULL; 520 drm_map_t *map = NULL;
524 drm_map_list_t *r_list;
525 unsigned long offset = 0; 521 unsigned long offset = 0;
526 struct list_head *list; 522 drm_hash_item_t *hash;
527 523
528 DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", 524 DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
529 vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); 525 vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
@@ -543,23 +539,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
543 ) 539 )
544 return drm_mmap_dma(filp, vma); 540 return drm_mmap_dma(filp, vma);
545 541
546 /* A sequential search of a linked list is 542 if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
547 fine here because: 1) there will only be 543 DRM_ERROR("Could not find map\n");
548 about 5-10 entries in the list and, 2) a 544 return -EINVAL;
549 DRI client only has to do this mapping
550 once, so it doesn't have to be optimized
551 for performance, even if the list was a
552 bit longer. */
553 list_for_each(list, &dev->maplist->head) {
554
555 r_list = list_entry(list, drm_map_list_t, head);
556 map = r_list->map;
557 if (!map)
558 continue;
559 if (r_list->user_token == vma->vm_pgoff << PAGE_SHIFT)
560 break;
561 } 545 }
562 546
547 map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
563 if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) 548 if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
564 return -EPERM; 549 return -EPERM;
565 550